mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Add support for : slices. Version bumped to 0.2.16
This commit is contained in:
committed by
Christoffer Lerno
parent
48a31cfa48
commit
4beb7eff8f
@@ -76,7 +76,7 @@ private fn void! out_str(PrintParam* param, variant arg)
|
||||
if (inner.kind == TypeKind.ARRAY && inner.inner == char.typeid)
|
||||
{
|
||||
char *ptr = *(char**)arg.ptr;
|
||||
return out_substr(param, ptr[0..inner.len - 1]);
|
||||
return out_substr(param, ptr[:inner.len]);
|
||||
}
|
||||
return ntoa_variant(param, arg, 16);
|
||||
case SIGNED_INT:
|
||||
@@ -272,7 +272,7 @@ private fn void! ntoa_format(PrintParam* param, char[] buf, usize len, bool nega
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
if (!len) return;
|
||||
return param.out_reverse(buf[0..len - 1]);
|
||||
return param.out_reverse(buf[:len]);
|
||||
}
|
||||
|
||||
$if (env::I128_SUPPORT):
|
||||
@@ -309,7 +309,7 @@ private fn void! ntoa(PrintParam* param, NtoaType value, bool negative, uint bas
|
||||
}
|
||||
while (value);
|
||||
}
|
||||
return ntoa_format(param, buf[..PRINTF_NTOA_BUFFER_SIZE - 1], len, negative, base);
|
||||
return ntoa_format(param, buf[:PRINTF_NTOA_BUFFER_SIZE], len, negative, base);
|
||||
}
|
||||
|
||||
|
||||
@@ -449,7 +449,7 @@ private fn void! ftoa(PrintParam* param, FloatType value)
|
||||
if (len >= PRINTF_FTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
buf[len++] = next;
|
||||
}
|
||||
return param.out_reverse(buf[..len-1]);
|
||||
return param.out_reverse(buf[:len]);
|
||||
}
|
||||
|
||||
union ConvUnion
|
||||
|
||||
@@ -708,6 +708,7 @@ typedef struct
|
||||
{
|
||||
bool start_from_back : 1;
|
||||
bool end_from_back : 1;
|
||||
bool is_lenrange : 1;
|
||||
ExprId expr;
|
||||
ExprId start;
|
||||
ExprId end;
|
||||
|
||||
@@ -2265,7 +2265,7 @@ static void llvm_emit_trap_invalid_shift(GenContext *c, LLVMValueRef value, Type
|
||||
}
|
||||
}
|
||||
|
||||
static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_ref, BEValue *start_ref, BEValue *end_ref)
|
||||
static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_ref, BEValue *start_ref, BEValue *end_ref, bool *is_exclusive)
|
||||
{
|
||||
assert(slice->expr_kind == EXPR_SLICE);
|
||||
|
||||
@@ -2351,7 +2351,7 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r
|
||||
|
||||
Type *end_type;
|
||||
BEValue end_index;
|
||||
|
||||
bool is_len_range = *is_exclusive = slice->slice_expr.is_lenrange;
|
||||
if (end)
|
||||
{
|
||||
// Get the index.
|
||||
@@ -2365,9 +2365,13 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r
|
||||
end_index.value = llvm_emit_sub_int(c, end_type, len.value, end_index.value, slice->span);
|
||||
llvm_value_rvalue(c, &end_index);
|
||||
}
|
||||
if (is_len_range)
|
||||
{
|
||||
end_index.value = llvm_emit_add_int(c, end_type, start_index.value, end_index.value, slice->span);
|
||||
}
|
||||
|
||||
// This will trap any bad negative index, so we're fine.
|
||||
if (active_target.feature.safe_mode)
|
||||
if (active_target.feature.safe_mode && !is_len_range)
|
||||
{
|
||||
BEValue excess;
|
||||
llvm_emit_int_comparison(c, &excess, &start_index, &end_index, BINARYOP_GT);
|
||||
@@ -2375,7 +2379,6 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r
|
||||
|
||||
if (len.value)
|
||||
{
|
||||
|
||||
llvm_emit_int_comparison(c, &excess, &len, &end_index, BINARYOP_LT);
|
||||
llvm_emit_panic_if_true(c, &excess, "Size exceeds index", slice->span);
|
||||
}
|
||||
@@ -2384,9 +2387,10 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r
|
||||
else
|
||||
{
|
||||
assert(len.value && "Pointer should never end up here.");
|
||||
// Otherwise everything is fine and dandy. Our len - 1 is our end index.
|
||||
end_index.value = LLVMBuildSub(c->builder, len.value, LLVMConstInt(LLVMTypeOf(len.value), 1, false), "");
|
||||
end_index.value = len.value;
|
||||
end_type = type_usize;
|
||||
// Use "len-range" when implicit, this avoids len - 1 here.
|
||||
*is_exclusive = true;
|
||||
}
|
||||
|
||||
llvm_value_set(end_ref, end_index.value, end_type);
|
||||
@@ -2400,13 +2404,22 @@ static void gencontext_emit_slice(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
BEValue parent;
|
||||
BEValue start;
|
||||
BEValue end;
|
||||
llvm_emit_slice_values(c, expr, &parent, &start, &end);
|
||||
bool is_exclusive;
|
||||
llvm_emit_slice_values(c, expr, &parent, &start, &end, &is_exclusive);
|
||||
llvm_value_rvalue(c, &start);
|
||||
llvm_value_rvalue(c, &end);
|
||||
|
||||
|
||||
// Calculate the size
|
||||
LLVMValueRef size = LLVMBuildSub(c->builder, LLVMBuildAdd(c->builder, end.value, llvm_const_int(c, start.type, 1), ""), start.value, "size");
|
||||
LLVMValueRef size;
|
||||
if (is_exclusive)
|
||||
{
|
||||
size = LLVMBuildSub(c->builder, end.value, start.value, "size");
|
||||
}
|
||||
else
|
||||
{
|
||||
size = LLVMBuildSub(c->builder, LLVMBuildAdd(c->builder, end.value, llvm_const_int(c, start.type, 1), ""), start.value, "size");
|
||||
}
|
||||
LLVMValueRef start_pointer;
|
||||
Type *type = type_lowering(parent.type);
|
||||
switch (type->type_kind)
|
||||
@@ -2452,7 +2465,8 @@ static void llvm_emit_slice_assign(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
BEValue start;
|
||||
BEValue end;
|
||||
// Use general function to get all the values we need (a lot!)
|
||||
llvm_emit_slice_values(c, exprptr(expr->slice_assign_expr.left), &parent, &start, &end);
|
||||
bool is_exclusive;
|
||||
llvm_emit_slice_values(c, exprptr(expr->slice_assign_expr.left), &parent, &start, &end, &is_exclusive);
|
||||
llvm_value_rvalue(c, &start);
|
||||
llvm_value_rvalue(c, &end);
|
||||
|
||||
@@ -2468,6 +2482,11 @@ static void llvm_emit_slice_assign(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
assert(start_val <= INT64_MAX);
|
||||
assert(end_val <= INT64_MAX);
|
||||
if (start_val > end_val) return;
|
||||
if (is_exclusive)
|
||||
{
|
||||
if (start_val == end_val) return;
|
||||
end_val--;
|
||||
}
|
||||
if (end_val - start_val < SLICE_MAX_UNROLL)
|
||||
{
|
||||
BEValue addr;
|
||||
@@ -2503,7 +2522,8 @@ static void llvm_emit_slice_assign(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
|
||||
// Check if we're not at the end.
|
||||
BEValue value;
|
||||
llvm_emit_int_comp(c, &value, start.type, end.type, offset, end.value, BINARYOP_LE);
|
||||
BinaryOp op = is_exclusive ? BINARYOP_LT : BINARYOP_LE;
|
||||
llvm_emit_int_comp(c, &value, start.type, end.type, offset, end.value, op);
|
||||
|
||||
// If jump to the assign block if we're not at the end index.
|
||||
EMIT_LOC(c, expr);
|
||||
|
||||
@@ -827,14 +827,16 @@ static void gencontext_emit_switch_body(GenContext *c, BEValue *switch_value, As
|
||||
llvm_value_rvalue(c, &be_value);
|
||||
case_value = be_value.value;
|
||||
LLVMAddCase(switch_stmt, case_value, block);
|
||||
Expr *to = case_stmt->case_stmt.to_expr;
|
||||
if (to)
|
||||
Expr *to_expr =case_stmt->case_stmt.to_expr;
|
||||
if (to_expr)
|
||||
{
|
||||
BEValue to_value;
|
||||
llvm_emit_expr(c, &to_value, case_stmt->case_stmt.to_expr);
|
||||
assert(LLVMIsAConstant(to_value.value));
|
||||
llvm_emit_expr(c, &to_value, to_expr);
|
||||
llvm_value_rvalue(c, &to_value);
|
||||
LLVMValueRef to = to_value.value;
|
||||
assert(LLVMIsAConstant(to));
|
||||
LLVMValueRef one = llvm_const_int(c, to_value.type, 1);
|
||||
while (LLVMConstIntGetZExtValue(LLVMConstICmp(LLVMIntEQ, to_value.value, case_value)) != 1)
|
||||
while (LLVMConstIntGetZExtValue(LLVMConstICmp(LLVMIntEQ, to, case_value)) != 1)
|
||||
{
|
||||
case_value = LLVMConstAdd(case_value, one);
|
||||
LLVMAddCase(switch_stmt, case_value, block);
|
||||
|
||||
@@ -752,7 +752,7 @@ static Expr *parse_subscript_expr(ParseContext *c, Expr *left)
|
||||
Expr *end = NULL;
|
||||
|
||||
// Not range with missing entry
|
||||
if (!tok_is(c, TOKEN_DOTDOT))
|
||||
if (!tok_is(c, TOKEN_DOTDOT) && !tok_is(c, TOKEN_COLON))
|
||||
{
|
||||
// Might be ^ prefix
|
||||
from_back = try_consume(c, TOKEN_BIT_XOR);
|
||||
@@ -765,7 +765,8 @@ static Expr *parse_subscript_expr(ParseContext *c, Expr *left)
|
||||
index->resolve_status = RESOLVE_DONE;
|
||||
expr_const_set_int(&index->const_expr, 0, type_uint->type_kind);
|
||||
}
|
||||
if (try_consume(c, TOKEN_DOTDOT))
|
||||
bool is_len_range = try_consume(c, TOKEN_COLON);
|
||||
if (is_len_range || try_consume(c, TOKEN_DOTDOT))
|
||||
{
|
||||
is_range = true;
|
||||
if (!tok_is(c, TOKEN_RBRACKET))
|
||||
@@ -785,6 +786,7 @@ static Expr *parse_subscript_expr(ParseContext *c, Expr *left)
|
||||
subs_expr->slice_expr.start_from_back = from_back;
|
||||
subs_expr->slice_expr.end = end ? exprid(end) : 0;
|
||||
subs_expr->slice_expr.end_from_back = end_from_back;
|
||||
subs_expr->slice_expr.is_lenrange = is_len_range;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -296,9 +296,21 @@ static inline Ast* parse_switch_stmt(ParseContext *c)
|
||||
Ast *switch_ast = new_ast(AST_SWITCH_STMT, c->span);
|
||||
advance_and_verify(c, TOKEN_SWITCH);
|
||||
ASSIGN_DECL_OR_RET(switch_ast->switch_stmt.flow.label, parse_optional_label(c, switch_ast), poisoned_ast);
|
||||
CONSUME_OR_RET(TOKEN_LPAREN, poisoned_ast);
|
||||
ASSIGN_EXPRID_OR_RET(switch_ast->switch_stmt.cond, parse_cond(c), poisoned_ast);
|
||||
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast);
|
||||
if (!try_consume(c, TOKEN_LPAREN))
|
||||
{
|
||||
Expr *cond = expr_new(EXPR_COND, switch_ast->span);
|
||||
Expr *expr = expr_new(EXPR_CONST, switch_ast->span);
|
||||
expr_const_set_bool(&expr->const_expr, true);
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
expr->type = type_bool;
|
||||
vec_add(cond->cond_expr, expr);
|
||||
switch_ast->switch_stmt.cond = exprid(cond);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSIGN_EXPRID_OR_RET(switch_ast->switch_stmt.cond, parse_cond(c), poisoned_ast);
|
||||
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast);
|
||||
}
|
||||
|
||||
if (!parse_switch_body(c, &switch_ast->switch_stmt.cases, TOKEN_CASE, TOKEN_DEFAULT)) return poisoned_ast;
|
||||
return switch_ast;
|
||||
|
||||
@@ -2479,6 +2479,64 @@ static void sema_deref_array_pointers(Expr *expr)
|
||||
}
|
||||
}
|
||||
|
||||
static bool expr_check_len_in_range(SemaContext *context, Type *type, Expr *len_expr, bool from_end, bool *remove_from_end)
|
||||
{
|
||||
assert(type == type->canonical);
|
||||
if (len_expr->expr_kind != EXPR_CONST) return true;
|
||||
|
||||
Int const_len = len_expr->const_expr.ixx;
|
||||
if (!int_fits(const_len, TYPE_I64))
|
||||
{
|
||||
SEMA_ERROR(len_expr, "The length cannot be stored in a 64-signed integer, which isn't supported.");
|
||||
return false;
|
||||
}
|
||||
if (int_is_neg(const_len))
|
||||
{
|
||||
SEMA_ERROR(len_expr, "The length may not be negative.");
|
||||
return false;
|
||||
}
|
||||
MemberIndex len_val = (MemberIndex)const_len.i.low;
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_POINTER:
|
||||
case TYPE_FLEXIBLE_ARRAY:
|
||||
assert(!from_end);
|
||||
FALLTHROUGH;
|
||||
case TYPE_SUBARRAY:
|
||||
return true;
|
||||
case TYPE_ARRAY:
|
||||
case TYPE_VECTOR:
|
||||
{
|
||||
MemberIndex len = (MemberIndex)type->array.len;
|
||||
bool is_vector = type->type_kind == TYPE_VECTOR;
|
||||
if (from_end)
|
||||
{
|
||||
if (len_val > len)
|
||||
{
|
||||
SEMA_ERROR(len_expr, "This would result in a negative length.");
|
||||
return false;
|
||||
}
|
||||
len_expr->const_expr.ixx.i.low = len - len_val;
|
||||
*remove_from_end = true;
|
||||
return true;
|
||||
}
|
||||
// Checking end can only be done for arrays and vectors.
|
||||
if (len_val > len)
|
||||
{
|
||||
SEMA_ERROR(len_expr,
|
||||
is_vector ? "Length out of bounds, was %lld, exceeding vector length %lld."
|
||||
: "Array length out of bounds, was %lld, exceeding array length %lld.",
|
||||
(long long)len_val, (long long)len);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
static bool expr_check_index_in_range(SemaContext *context, Type *type, Expr *index_expr, bool end_index, bool from_end, bool *remove_from_end)
|
||||
{
|
||||
assert(type == type->canonical);
|
||||
@@ -2799,6 +2857,11 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr)
|
||||
// Fix index sizes
|
||||
if (!expr_cast_to_index(start)) return false;
|
||||
if (end && !expr_cast_to_index(end)) return false;
|
||||
if (end && end->type != start->type)
|
||||
{
|
||||
Type *common = type_find_max_type(start->type, end->type);
|
||||
if (!common || !cast_implicit(start, common) || !cast_implicit(end, common)) return false;
|
||||
}
|
||||
|
||||
// Check range
|
||||
if (type->type_kind == TYPE_POINTER)
|
||||
@@ -2819,30 +2882,27 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool is_lenrange = expr->slice_expr.is_lenrange;
|
||||
bool remove_from_end = false;
|
||||
if (!expr_check_index_in_range(context, type, start, false, expr->slice_expr.start_from_back, &remove_from_end)) return false;
|
||||
if (remove_from_end) expr->slice_expr.start_from_back = false;
|
||||
remove_from_end = false;
|
||||
if (end && !expr_check_index_in_range(context, type, end, true, expr->slice_expr.end_from_back, &remove_from_end)) return false;
|
||||
if (end)
|
||||
{
|
||||
if (is_lenrange)
|
||||
{
|
||||
if (!expr_check_len_in_range(context, type, end, expr->slice_expr.end_from_back, &remove_from_end)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!expr_check_index_in_range(context, type, end, true, expr->slice_expr.end_from_back, &remove_from_end)) return false;
|
||||
}
|
||||
}
|
||||
if (remove_from_end) expr->slice_expr.end_from_back = false;
|
||||
|
||||
if (start && end && start->expr_kind == EXPR_CONST && end->expr_kind == EXPR_CONST)
|
||||
{
|
||||
if (type->type_kind == TYPE_ARRAY)
|
||||
{
|
||||
Int128 len = { 0, type->array.len };
|
||||
if (expr->slice_expr.start_from_back)
|
||||
{
|
||||
start->const_expr.ixx.i = i128_sub(len, start->const_expr.ixx.i);
|
||||
expr->slice_expr.start_from_back = false;
|
||||
}
|
||||
if (expr->slice_expr.end_from_back)
|
||||
{
|
||||
end->const_expr.ixx.i = i128_sub(len, end->const_expr.ixx.i);
|
||||
expr->slice_expr.end_from_back = false;
|
||||
}
|
||||
}
|
||||
if (expr->slice_expr.start_from_back && expr->slice_expr.end_from_back)
|
||||
if (!is_lenrange && expr->slice_expr.start_from_back && expr->slice_expr.end_from_back)
|
||||
{
|
||||
if (expr_const_compare(&start->const_expr, &end->const_expr, BINARYOP_LT))
|
||||
{
|
||||
@@ -2850,7 +2910,7 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!expr->slice_expr.start_from_back && !expr->slice_expr.end_from_back)
|
||||
else if (!is_lenrange && !expr->slice_expr.start_from_back && !expr->slice_expr.end_from_back)
|
||||
{
|
||||
if (expr_const_compare(&start->const_expr, &end->const_expr, BINARYOP_GT))
|
||||
{
|
||||
@@ -2858,6 +2918,17 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// If both are
|
||||
if (type->type_kind == TYPE_ARRAY || type->type_kind == TYPE_VECTOR)
|
||||
{
|
||||
assert(!expr->slice_expr.start_from_back);
|
||||
assert(!expr->slice_expr.end_from_back);
|
||||
if (!is_lenrange)
|
||||
{
|
||||
end->const_expr.ixx = int_sub(int_add64(end->const_expr.ixx, 1), start->const_expr.ixx);
|
||||
is_lenrange = expr->slice_expr.is_lenrange = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.2.15"
|
||||
#define COMPILER_VERSION "0.2.16"
|
||||
@@ -18,10 +18,6 @@ fn void main()
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
|
||||
|
||||
declare void @printf(i8*, ...) #0
|
||||
|
||||
define void @test.main() #0 {
|
||||
entry:
|
||||
%x = alloca [8 x i32], align 16
|
||||
@@ -45,12 +41,10 @@ entry:
|
||||
store i32 52, i32* %7, align 4
|
||||
store i64 0, i64* %anon, align 8
|
||||
br label %loop.cond
|
||||
|
||||
loop.cond: ; preds = %loop.body, %entry
|
||||
%8 = load i64, i64* %anon, align 8
|
||||
%gt = icmp ugt i64 8, %8
|
||||
br i1 %gt, label %loop.body, label %loop.exit
|
||||
|
||||
loop.body: ; preds = %loop.cond
|
||||
%9 = load i64, i64* %anon, align 8
|
||||
%10 = getelementptr inbounds [8 x i32], [8 x i32]* %x, i64 0, i64 %9
|
||||
@@ -62,27 +56,18 @@ loop.body: ; preds = %loop.cond
|
||||
%add = add i64 %13, 1
|
||||
store i64 %add, i64* %anon, align 8
|
||||
br label %loop.cond
|
||||
|
||||
loop.exit: ; preds = %loop.cond
|
||||
br label %cond
|
||||
|
||||
cond: ; preds = %assign, %loop.exit
|
||||
%14 = phi i64 [ 0, %loop.exit ], [ %add1, %assign ]
|
||||
%le = icmp sle i64 %14, 7
|
||||
br i1 %le, label %assign, label %exit
|
||||
|
||||
%lt = icmp slt i64 %14, 8
|
||||
br i1 %lt, label %assign, label %exit
|
||||
assign: ; preds = %cond
|
||||
%15 = getelementptr inbounds [8 x i32], [8 x i32]* %x, i64 0, i64 %14
|
||||
store i32 123, i32* %15, align 4
|
||||
%add1 = add i64 %14, 1
|
||||
br label %cond
|
||||
|
||||
exit: ; preds = %cond
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @main(i32 %0, i8** %1) #0 {
|
||||
entry:
|
||||
call void @test.main()
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// #target: macos-x64
|
||||
module mymodule;
|
||||
|
||||
extern fn void printf(char *, ...);
|
||||
@@ -49,9 +50,195 @@ fn void test()
|
||||
default:
|
||||
printf("None of the above\n");
|
||||
}
|
||||
switch
|
||||
{
|
||||
case a < 0:
|
||||
printf("A negative\n");
|
||||
case a == 1:
|
||||
printf("A is 1\n");
|
||||
default:
|
||||
printf("Unexpected a\n");
|
||||
}
|
||||
}
|
||||
fn void main()
|
||||
{
|
||||
test();
|
||||
printf("Hello!\n");
|
||||
}
|
||||
|
||||
/* #expect: mymodule.ll
|
||||
|
||||
define void @mymodule.test() #0 {
|
||||
entry:
|
||||
%x = alloca i32, align 4
|
||||
%x.f = alloca i64, align 8
|
||||
%z = alloca i64, align 8
|
||||
%err = alloca i64, align 8
|
||||
%switch = alloca i64, align 8
|
||||
%switch4 = alloca i64, align 8
|
||||
%a = alloca i32, align 4
|
||||
%b = alloca i32, align 4
|
||||
%zy = alloca i32, align 4
|
||||
%switch17 = alloca i32, align 4
|
||||
%switch27 = alloca i8, align 1
|
||||
store i64 ptrtoint (i8* @mymodule.ByeErr.BAR to i64), i64* %x.f, align 8
|
||||
store i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), i64* %z, align 8
|
||||
br label %testblock
|
||||
|
||||
testblock: ; preds = %entry
|
||||
%0 = load i64, i64* %x.f, align 8
|
||||
%not_err = icmp eq i64 %0, 0
|
||||
br i1 %not_err, label %after_check, label %error
|
||||
|
||||
error: ; preds = %testblock
|
||||
store i64 %0, i64* %err, align 8
|
||||
br label %end_block
|
||||
|
||||
after_check: ; preds = %testblock
|
||||
store i64 0, i64* %err, align 8
|
||||
br label %end_block
|
||||
|
||||
end_block: ; preds = %after_check, %error
|
||||
%1 = load i64, i64* %err, align 8
|
||||
%neq = icmp ne i64 %1, 0
|
||||
br i1 %neq, label %if.then, label %if.exit
|
||||
|
||||
if.then: ; preds = %end_block
|
||||
store i64 %1, i64* %switch, align 8
|
||||
br label %switch.entry
|
||||
|
||||
switch.entry: ; preds = %if.then
|
||||
%2 = load i64, i64* %switch, align 8
|
||||
%eq = icmp eq i64 ptrtoint (i8* @mymodule.HelloErr.FOO to i64), %2
|
||||
br i1 %eq, label %switch.case, label %next_if
|
||||
|
||||
switch.case: ; preds = %switch.entry
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i32 0, i32 0))
|
||||
br label %switch.exit
|
||||
|
||||
next_if: ; preds = %switch.entry
|
||||
%eq1 = icmp eq i64 ptrtoint (i8* @mymodule.ByeErr.BAR to i64), %2
|
||||
br i1 %eq1, label %switch.case2, label %next_if3
|
||||
|
||||
switch.case2: ; preds = %next_if
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i32 0, i32 0))
|
||||
br label %switch.exit
|
||||
|
||||
next_if3: ; preds = %next_if
|
||||
br label %switch.default
|
||||
|
||||
switch.default: ; preds = %next_if3
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.2, i32 0, i32 0))
|
||||
br label %switch.exit
|
||||
|
||||
switch.exit: ; preds = %switch.default, %switch.case2, %switch.case
|
||||
br label %if.exit
|
||||
|
||||
if.exit: ; preds = %switch.exit, %end_block
|
||||
%3 = load i64, i64* %z, align 8
|
||||
store i64 %3, i64* %switch4, align 8
|
||||
br label %switch.entry5
|
||||
|
||||
switch.entry5: ; preds = %if.exit
|
||||
%4 = load i64, i64* %switch4, align 8
|
||||
%eq6 = icmp eq i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), %4
|
||||
br i1 %eq6, label %switch.case7, label %next_if8
|
||||
|
||||
switch.case7: ; preds = %switch.entry5
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.3, i32 0, i32 0))
|
||||
br label %switch.exit16
|
||||
|
||||
next_if8: ; preds = %switch.entry5
|
||||
%eq9 = icmp eq i64 ptrtoint ({ i8 }* @.typeid.bool to i64), %4
|
||||
br i1 %eq9, label %switch.case10, label %next_if11
|
||||
|
||||
switch.case10: ; preds = %next_if8
|
||||
br label %switch.case13
|
||||
|
||||
next_if11: ; preds = %next_if8
|
||||
%eq12 = icmp eq i64 ptrtoint ({ i8, i16 }* @.typeid.double to i64), %4
|
||||
br i1 %eq12, label %switch.case13, label %next_if14
|
||||
|
||||
switch.case13: ; preds = %next_if11, %switch.case10
|
||||
br label %switch.default15
|
||||
|
||||
next_if14: ; preds = %next_if11
|
||||
br label %switch.default15
|
||||
|
||||
switch.default15: ; preds = %next_if14, %switch.case13
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.4, i32 0, i32 0))
|
||||
br label %switch.exit16
|
||||
|
||||
switch.exit16: ; preds = %switch.default15, %switch.case7
|
||||
store i32 1, i32* %a, align 4
|
||||
store i32 2, i32* %b, align 4
|
||||
%5 = load i32, i32* %b, align 4
|
||||
%6 = load i32, i32* %a, align 4
|
||||
%add = add i32 %5, %6
|
||||
store i32 %add, i32* %zy, align 4
|
||||
%7 = load i32, i32* %zy, align 4
|
||||
store i32 %7, i32* %switch17, align 4
|
||||
br label %switch.entry18
|
||||
|
||||
switch.entry18: ; preds = %switch.exit16
|
||||
%8 = load i32, i32* %switch17, align 4
|
||||
%9 = load i32, i32* %a, align 4
|
||||
%eq19 = icmp eq i32 %9, %8
|
||||
br i1 %eq19, label %switch.case20, label %next_if21
|
||||
|
||||
switch.case20: ; preds = %switch.entry18
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.5, i32 0, i32 0))
|
||||
br label %switch.exit26
|
||||
|
||||
next_if21: ; preds = %switch.entry18
|
||||
%10 = load i32, i32* %b, align 4
|
||||
%eq22 = icmp eq i32 %10, %8
|
||||
br i1 %eq22, label %switch.case23, label %next_if24
|
||||
|
||||
switch.case23: ; preds = %next_if21
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.6, i32 0, i32 0))
|
||||
br label %switch.exit26
|
||||
|
||||
next_if24: ; preds = %next_if21
|
||||
br label %switch.default25
|
||||
|
||||
switch.default25: ; preds = %next_if24
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([19 x i8], [19 x i8]* @.str.7, i32 0, i32 0))
|
||||
br label %switch.exit26
|
||||
|
||||
switch.exit26: ; preds = %switch.default25, %switch.case23, %switch.case20
|
||||
store i8 1, i8* %switch27, align 1
|
||||
br label %switch.entry28
|
||||
|
||||
switch.entry28: ; preds = %switch.exit26
|
||||
%11 = load i8, i8* %switch27, align 1
|
||||
%12 = trunc i8 %11 to i1
|
||||
%13 = load i32, i32* %a, align 4
|
||||
%lt = icmp slt i32 %13, 0
|
||||
%eq29 = icmp eq i1 %lt, %12
|
||||
br i1 %eq29, label %switch.case30, label %next_if31
|
||||
|
||||
switch.case30: ; preds = %switch.entry28
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.8, i32 0, i32 0))
|
||||
br label %switch.exit37
|
||||
|
||||
next_if31: ; preds = %switch.entry28
|
||||
%14 = load i32, i32* %a, align 4
|
||||
%eq32 = icmp eq i32 %14, 1
|
||||
%eq33 = icmp eq i1 %eq32, %12
|
||||
br i1 %eq33, label %switch.case34, label %next_if35
|
||||
|
||||
switch.case34: ; preds = %next_if31
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.9, i32 0, i32 0))
|
||||
br label %switch.exit37
|
||||
|
||||
next_if35: ; preds = %next_if31
|
||||
br label %switch.default36
|
||||
|
||||
switch.default36: ; preds = %next_if35
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.10, i32 0, i32 0))
|
||||
br label %switch.exit37
|
||||
|
||||
switch.exit37: ; preds = %switch.default36, %switch.case34, %switch.case30
|
||||
ret void
|
||||
}
|
||||
@@ -23,7 +23,6 @@ fn void main()
|
||||
; Function Attrs: nounwind
|
||||
declare void @printf(ptr, ...) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @test.main() #0 {
|
||||
entry:
|
||||
%x = alloca [8 x i32], align 16
|
||||
@@ -69,8 +68,8 @@ loop.exit: ; preds = %loop.cond
|
||||
|
||||
cond: ; preds = %assign, %loop.exit
|
||||
%13 = phi i64 [ 0, %loop.exit ], [ %add1, %assign ]
|
||||
%le = icmp sle i64 %13, 7
|
||||
br i1 %le, label %assign, label %exit
|
||||
%lt = icmp slt i64 %13, 8
|
||||
br i1 %lt, label %assign, label %exit
|
||||
|
||||
assign: ; preds = %cond
|
||||
%14 = getelementptr inbounds [8 x i32], ptr %x, i64 0, i64 %13
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// #target: macos-x64
|
||||
module mymodule;
|
||||
|
||||
extern fn void printf(char *, ...);
|
||||
@@ -49,9 +50,195 @@ fn void test()
|
||||
default:
|
||||
printf("None of the above\n");
|
||||
}
|
||||
switch
|
||||
{
|
||||
case a < 0:
|
||||
printf("A negative\n");
|
||||
case a == 1:
|
||||
printf("A is 1\n");
|
||||
default:
|
||||
printf("Unexpected a\n");
|
||||
}
|
||||
}
|
||||
fn void main()
|
||||
{
|
||||
test();
|
||||
printf("Hello!\n");
|
||||
}
|
||||
|
||||
/* #expect: mymodule.ll
|
||||
|
||||
define void @mymodule.test() #0 {
|
||||
entry:
|
||||
%x = alloca i32, align 4
|
||||
%x.f = alloca i64, align 8
|
||||
%z = alloca i64, align 8
|
||||
%err = alloca i64, align 8
|
||||
%switch = alloca i64, align 8
|
||||
%switch4 = alloca i64, align 8
|
||||
%a = alloca i32, align 4
|
||||
%b = alloca i32, align 4
|
||||
%zy = alloca i32, align 4
|
||||
%switch17 = alloca i32, align 4
|
||||
%switch27 = alloca i8, align 1
|
||||
store i64 ptrtoint (ptr @mymodule.ByeErr.BAR to i64), ptr %x.f, align 8
|
||||
store i64 ptrtoint (ptr @.typeid.int to i64), ptr %z, align 8
|
||||
br label %testblock
|
||||
|
||||
testblock: ; preds = %entry
|
||||
%0 = load i64, ptr %x.f, align 8
|
||||
%not_err = icmp eq i64 %0, 0
|
||||
br i1 %not_err, label %after_check, label %error
|
||||
|
||||
error: ; preds = %testblock
|
||||
store i64 %0, ptr %err, align 8
|
||||
br label %end_block
|
||||
|
||||
after_check: ; preds = %testblock
|
||||
store i64 0, ptr %err, align 8
|
||||
br label %end_block
|
||||
|
||||
end_block: ; preds = %after_check, %error
|
||||
%1 = load i64, ptr %err, align 8
|
||||
%neq = icmp ne i64 %1, 0
|
||||
br i1 %neq, label %if.then, label %if.exit
|
||||
|
||||
if.then: ; preds = %end_block
|
||||
store i64 %1, ptr %switch, align 8
|
||||
br label %switch.entry
|
||||
|
||||
switch.entry: ; preds = %if.then
|
||||
%2 = load i64, ptr %switch, align 8
|
||||
%eq = icmp eq i64 ptrtoint (ptr @mymodule.HelloErr.FOO to i64), %2
|
||||
br i1 %eq, label %switch.case, label %next_if
|
||||
|
||||
switch.case: ; preds = %switch.entry
|
||||
call void (ptr, ...) @printf(ptr @.str)
|
||||
br label %switch.exit
|
||||
|
||||
next_if: ; preds = %switch.entry
|
||||
%eq1 = icmp eq i64 ptrtoint (ptr @mymodule.ByeErr.BAR to i64), %2
|
||||
br i1 %eq1, label %switch.case2, label %next_if3
|
||||
|
||||
switch.case2: ; preds = %next_if
|
||||
call void (ptr, ...) @printf(ptr @.str.1)
|
||||
br label %switch.exit
|
||||
|
||||
next_if3: ; preds = %next_if
|
||||
br label %switch.default
|
||||
|
||||
switch.default: ; preds = %next_if3
|
||||
call void (ptr, ...) @printf(ptr @.str.2)
|
||||
br label %switch.exit
|
||||
|
||||
switch.exit: ; preds = %switch.default, %switch.case2, %switch.case
|
||||
br label %if.exit
|
||||
|
||||
if.exit: ; preds = %switch.exit, %end_block
|
||||
%3 = load i64, ptr %z, align 8
|
||||
store i64 %3, ptr %switch4, align 8
|
||||
br label %switch.entry5
|
||||
|
||||
switch.entry5: ; preds = %if.exit
|
||||
%4 = load i64, ptr %switch4, align 8
|
||||
%eq6 = icmp eq i64 ptrtoint (ptr @.typeid.int to i64), %4
|
||||
br i1 %eq6, label %switch.case7, label %next_if8
|
||||
|
||||
switch.case7: ; preds = %switch.entry5
|
||||
call void (ptr, ...) @printf(ptr @.str.3)
|
||||
br label %switch.exit16
|
||||
|
||||
next_if8: ; preds = %switch.entry5
|
||||
%eq9 = icmp eq i64 ptrtoint (ptr @.typeid.bool to i64), %4
|
||||
br i1 %eq9, label %switch.case10, label %next_if11
|
||||
|
||||
switch.case10: ; preds = %next_if8
|
||||
br label %switch.case13
|
||||
|
||||
next_if11: ; preds = %next_if8
|
||||
%eq12 = icmp eq i64 ptrtoint (ptr @.typeid.double to i64), %4
|
||||
br i1 %eq12, label %switch.case13, label %next_if14
|
||||
|
||||
switch.case13: ; preds = %next_if11, %switch.case10
|
||||
br label %switch.default15
|
||||
|
||||
next_if14: ; preds = %next_if11
|
||||
br label %switch.default15
|
||||
|
||||
switch.default15: ; preds = %next_if14, %switch.case13
|
||||
call void (ptr, ...) @printf(ptr @.str.4)
|
||||
br label %switch.exit16
|
||||
|
||||
switch.exit16: ; preds = %switch.default15, %switch.case7
|
||||
store i32 1, ptr %a, align 4
|
||||
store i32 2, ptr %b, align 4
|
||||
%5 = load i32, ptr %b, align 4
|
||||
%6 = load i32, ptr %a, align 4
|
||||
%add = add i32 %5, %6
|
||||
store i32 %add, ptr %zy, align 4
|
||||
%7 = load i32, ptr %zy, align 4
|
||||
store i32 %7, ptr %switch17, align 4
|
||||
br label %switch.entry18
|
||||
|
||||
switch.entry18: ; preds = %switch.exit16
|
||||
%8 = load i32, ptr %switch17, align 4
|
||||
%9 = load i32, ptr %a, align 4
|
||||
%eq19 = icmp eq i32 %9, %8
|
||||
br i1 %eq19, label %switch.case20, label %next_if21
|
||||
|
||||
switch.case20: ; preds = %switch.entry18
|
||||
call void (ptr, ...) @printf(ptr @.str.5)
|
||||
br label %switch.exit26
|
||||
|
||||
next_if21: ; preds = %switch.entry18
|
||||
%10 = load i32, ptr %b, align 4
|
||||
%eq22 = icmp eq i32 %10, %8
|
||||
br i1 %eq22, label %switch.case23, label %next_if24
|
||||
|
||||
switch.case23: ; preds = %next_if21
|
||||
call void (ptr, ...) @printf(ptr @.str.6)
|
||||
br label %switch.exit26
|
||||
|
||||
next_if24: ; preds = %next_if21
|
||||
br label %switch.default25
|
||||
|
||||
switch.default25: ; preds = %next_if24
|
||||
call void (ptr, ...) @printf(ptr @.str.7)
|
||||
br label %switch.exit26
|
||||
|
||||
switch.exit26: ; preds = %switch.default25, %switch.case23, %switch.case20
|
||||
store i8 1, ptr %switch27, align 1
|
||||
br label %switch.entry28
|
||||
|
||||
switch.entry28: ; preds = %switch.exit26
|
||||
%11 = load i8, ptr %switch27, align 1
|
||||
%12 = trunc i8 %11 to i1
|
||||
%13 = load i32, ptr %a, align 4
|
||||
%lt = icmp slt i32 %13, 0
|
||||
%eq29 = icmp eq i1 %lt, %12
|
||||
br i1 %eq29, label %switch.case30, label %next_if31
|
||||
|
||||
switch.case30: ; preds = %switch.entry28
|
||||
call void (ptr, ...) @printf(ptr @.str.8)
|
||||
br label %switch.exit37
|
||||
|
||||
next_if31: ; preds = %switch.entry28
|
||||
%14 = load i32, ptr %a, align 4
|
||||
%eq32 = icmp eq i32 %14, 1
|
||||
%eq33 = icmp eq i1 %eq32, %12
|
||||
br i1 %eq33, label %switch.case34, label %next_if35
|
||||
|
||||
switch.case34: ; preds = %next_if31
|
||||
call void (ptr, ...) @printf(ptr @.str.9)
|
||||
br label %switch.exit37
|
||||
|
||||
next_if35: ; preds = %next_if31
|
||||
br label %switch.default36
|
||||
|
||||
switch.default36: ; preds = %next_if35
|
||||
call void (ptr, ...) @printf(ptr @.str.10)
|
||||
br label %switch.exit37
|
||||
|
||||
switch.exit37: ; preds = %switch.default36, %switch.case34, %switch.case30
|
||||
ret void
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user