Introduce def as a trial. Fixup of timeit.

This commit is contained in:
Christoffer Lerno
2023-04-21 17:42:38 +02:00
parent c847650579
commit 2a79e0f1cf
9 changed files with 125 additions and 53 deletions

View File

@@ -268,7 +268,7 @@ jobs:
python3 src/tester.py ../build/c3c test_suite/ python3 src/tester.py ../build/c3c test_suite/
- name: bundle_output - name: bundle_output
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION if: matrix.llvm_version == 16
run: | run: |
mkdir linux mkdir linux
cp -r lib linux cp -r lib linux
@@ -277,7 +277,7 @@ jobs:
tar czf c3-linux-${{matrix.build_type}}.tar.gz linux tar czf c3-linux-${{matrix.build_type}}.tar.gz linux
- name: upload artifacts - name: upload artifacts
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION if: matrix.llvm_version == 16
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: c3-linux-${{matrix.build_type}} name: c3-linux-${{matrix.build_type}}

View File

@@ -165,6 +165,7 @@
- Fix bug initializing nested struct/unions. - Fix bug initializing nested struct/unions.
- Fix of bool -> vector cast. - Fix of bool -> vector cast.
- Correctly widen C style varargs for distinct types and optionals. - Correctly widen C style varargs for distinct types and optionals.
- Fix of too aggressive codegen in ternary codegen with array indexing.
## 0.4.0 Change List ## 0.4.0 Change List

View File

@@ -0,0 +1,71 @@
module fannkuch;
import std::io;
import std::math;
fn int fannkuchredux(int n)
{
int[] perm = malloc(int, n)[:n];
int[] perm1 = malloc(int, n)[:n];
int* count = malloc(int, n);
int max_flips_count;
int perm_count;
int checksum;
foreach (int i, &v : perm1) *v = i;
int r = n;
while (true)
{
for (; r != 1; r--) count[r - 1] = r;
perm[..] = perm1[..];
int flips_count = 0;
int k;
while (!((k = perm[0]) == 0))
{
int k2 = (k + 1) >> 1;
for (int i = 0; i < k2; i++)
{
@swap(perm[i], perm[k - i]);
}
flips_count++;
}
max_flips_count = max(max_flips_count, flips_count);
checksum += perm_count % 2 == 0 ? flips_count : -flips_count;
/* Use incremental change to generate another permutation */
while (true)
{
if (r == n)
{
io::printf("%d\n", checksum);
return max_flips_count;
}
int perm0 = perm1[0];
int i = 0;
while (i < r)
{
int j = i + 1;
perm1[i] = perm1[j];
i = j;
}
perm1[r] = perm0;
count[r] -= 1;
if (count[r] > 0) break;
r++;
}
perm_count++;
}
return 0;
}
fn void! main(String[] argv)
{
int n = argv.len > 1 ? argv[1].to_int()!! : 7;
io::printf("Pfannkuchen(%d) = %d\n", n, fannkuchredux(n));
}

View File

@@ -17,7 +17,6 @@ static inline void llvm_emit_expression_list_expr(GenContext *c, BEValue *be_val
static inline void llvm_emit_bitassign_array(GenContext *c, BEValue *result, BEValue parent, Decl *parent_decl, Decl *member); static inline void llvm_emit_bitassign_array(GenContext *c, BEValue *result, BEValue parent, Decl *parent_decl, Decl *member);
static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Expr *expr); static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Expr *expr);
static inline void llvm_emit_const_initialize_reference(GenContext *c, BEValue *ref, Expr *expr); static inline void llvm_emit_const_initialize_reference(GenContext *c, BEValue *ref, Expr *expr);
static inline void llvm_emit_elvis_expr(GenContext *c, BEValue *value, Expr *expr);
static inline void llvm_emit_expr_block(GenContext *context, BEValue *be_value, Expr *expr); static inline void llvm_emit_expr_block(GenContext *context, BEValue *be_value, Expr *expr);
static inline void llvm_emit_optional(GenContext *c, BEValue *be_value, Expr *expr); static inline void llvm_emit_optional(GenContext *c, BEValue *be_value, Expr *expr);
static inline void llvm_emit_inc_dec_change(GenContext *c, BEValue *addr, BEValue *after, BEValue *before, Expr *expr, static inline void llvm_emit_inc_dec_change(GenContext *c, BEValue *addr, BEValue *after, BEValue *before, Expr *expr,
@@ -4238,85 +4237,86 @@ static void llvm_emit_binary_expr(GenContext *c, BEValue *be_value, Expr *expr)
static inline void llvm_emit_elvis_expr(GenContext *c, BEValue *value, Expr *expr) static inline void llvm_emit_elvis_expr(GenContext *c, BEValue *value, Expr *expr)
{ {
// Set up basic blocks, following Cone
LLVMBasicBlockRef phi_block = llvm_basic_block_new(c, "cond.phi"); LLVMBasicBlockRef phi_block = llvm_basic_block_new(c, "cond.phi");
LLVMBasicBlockRef rhs_block = llvm_basic_block_new(c, "cond.rhs"); LLVMBasicBlockRef rhs_block = llvm_basic_block_new(c, "cond.rhs");
// Generate condition and conditional branch // Generate condition and conditional branch
Expr *cond = exprptr(expr->ternary_expr.cond); Expr *cond = exprptr(expr->ternary_expr.cond);
llvm_emit_expr(c, value, cond); llvm_emit_expr(c, value, cond);
if (value->type == type_void) return;
// Get the Rvalue version (in case we have an address)
llvm_value_rvalue(c, value); llvm_value_rvalue(c, value);
LLVMValueRef lhs = value->value; LLVMValueRef lhs_value = value->value;
Type *cond_type = cond->type;
// If the cond is not a boolean, we need to do the cast.
if (value->kind != BE_BOOLEAN) if (value->kind != BE_BOOLEAN)
{ {
CastKind cast = cast_to_bool_kind(cond_type); CastKind cast = cast_to_bool_kind(value->type);
llvm_emit_cast(c, cast, cond, value, type_bool, cond_type); llvm_emit_cast(c, cast, cond, value, type_bool, value->type);
assert(value->kind == BE_BOOLEAN);
} }
Expr *else_expr = exprptr(expr->ternary_expr.else_expr); Expr *else_expr = exprptr(expr->ternary_expr.else_expr);
if (!IS_OPTIONAL(expr) && expr_is_constant_eval(else_expr, CONSTANT_EVAL_NO_SIDE_EFFECTS)) if (!IS_OPTIONAL(expr) && expr_is_const(else_expr))
{ {
BEValue right; BEValue right;
llvm_emit_expr(c, &right, else_expr); llvm_emit_expr(c, &right, else_expr);
llvm_value_rvalue(c, &right); llvm_value_rvalue(c, &right);
LLVMValueRef val = LLVMBuildSelect(c->builder, value->value, lhs, right.value, "elvis"); LLVMValueRef val = LLVMBuildSelect(c->builder, value->value, lhs_value, right.value, "elvis");
llvm_value_set(value, val, right.type); llvm_value_set(value, val, right.type);
return; return;
} }
LLVMBasicBlockRef lhs_exit = llvm_get_current_block_if_in_use(c); LLVMBasicBlockRef lhs_exit = llvm_get_current_block_if_in_use(c);
assert(lhs_exit); if (!lhs_exit) return;
llvm_emit_cond_br(c, value, phi_block, rhs_block); llvm_emit_cond_br(c, value, phi_block, rhs_block);
llvm_emit_block(c, rhs_block); llvm_emit_block(c, rhs_block);
// Emit right side: BEValue rhs;
llvm_emit_expr(c, value, else_expr); llvm_emit_expr(c, &rhs, else_expr);
// Lower to value. llvm_value_rvalue(c, &rhs);
llvm_value_rvalue(c, value); LLVMValueRef rhs_value = rhs.value;
if (rhs.type == type_bool && LLVMTypeOf(rhs_value) != c->bool_type)
LLVMBasicBlockRef rhs_exit = llvm_get_current_block_if_in_use(c);
// RHS may be a jump, in that case just emit the "phi" block.
if (!rhs_exit)
{ {
llvm_emit_block(c, phi_block); llvm_emit_trunc_bool(c, rhs_value);
return;
} }
LLVMBasicBlockRef rhs_exit = llvm_get_current_block_if_in_use(c);
llvm_emit_br(c, phi_block); if (rhs_exit) llvm_emit_br(c, phi_block);
// Generate phi // Generate phi
llvm_emit_block(c, phi_block); llvm_emit_block(c, phi_block);
if (!rhs_exit)
{
if (!lhs_value) lhs_value = LLVMGetUndef(llvm_get_type(c, expr->type));
llvm_value_set(value, lhs_value, expr->type);
return;
}
// If both sides are bool we produce a bool as well. if (!lhs_exit)
LLVMTypeRef phi_type = expr->type->canonical->type_kind == TYPE_BOOL ? c->bool_type : llvm_get_type(c, expr->type); {
LLVMValueRef phi = LLVMBuildPhi(c->builder, phi_type, "val"); if (!rhs_value) rhs_value = LLVMGetUndef(llvm_get_type(c, expr->type));
llvm_value_set(value, rhs_value, expr->type);
return;
}
LLVMValueRef logic_values[2] = { lhs, value->value }; Type *expr_type = type_flatten(expr->type);
LLVMTypeRef type = expr_type == type_bool ? c->bool_type : llvm_get_type(c, expr_type);
LLVMValueRef phi = LLVMBuildPhi(c->builder, type, "val");
LLVMValueRef logic_values[2] = { lhs_value, rhs_value };
LLVMBasicBlockRef blocks[2] = { lhs_exit, rhs_exit }; LLVMBasicBlockRef blocks[2] = { lhs_exit, rhs_exit };
LLVMAddIncoming(phi, logic_values, blocks, 2); LLVMAddIncoming(phi, logic_values, blocks, 2);
llvm_value_set(value, phi, expr_type);
// The rest of value should now be set to the right value.
value->value = phi;
} }
void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr) void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr)
{ {
bool is_elvis = !expr->ternary_expr.then_expr; if (!expr->ternary_expr.then_expr) return llvm_emit_elvis_expr(c, value, expr);
// Set up basic blocks, following Cone // Set up basic blocks, following Cone
LLVMBasicBlockRef phi_block = llvm_basic_block_new(c, "cond.phi"); LLVMBasicBlockRef phi_block = llvm_basic_block_new(c, "cond.phi");
LLVMBasicBlockRef lhs_block = llvm_basic_block_new(c, "cond.lhs"); LLVMBasicBlockRef lhs_block = llvm_basic_block_new(c, "cond.lhs");
LLVMBasicBlockRef rhs_block = llvm_basic_block_new(c, "cond.rhs"); LLVMBasicBlockRef rhs_block = llvm_basic_block_new(c, "cond.rhs");
bool is_elvis = false;
// Generate condition and conditional branch // Generate condition and conditional branch
Expr *cond = exprptr(expr->ternary_expr.cond); Expr *cond = exprptr(expr->ternary_expr.cond);
llvm_emit_expr(c, value, cond); llvm_emit_expr(c, value, cond);
@@ -4345,8 +4345,8 @@ void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr)
} }
if (!IS_OPTIONAL(expr) && expr_is_constant_eval(else_expr, CONSTANT_EVAL_NO_SIDE_EFFECTS) if (!IS_OPTIONAL(expr) && expr_is_const(else_expr)
&& (is_elvis || expr_is_constant_eval(then_expr, CONSTANT_EVAL_NO_SIDE_EFFECTS))) && (is_elvis || expr_is_const(then_expr)))
{ {
if (!lhs_value) if (!lhs_value)
{ {

View File

@@ -4,5 +4,5 @@ int foo @section("foo, 12345678901234567 "); // #error: Mach-o requires t
int bar @section("foo, "); // #error: Mach-o requires 'segment,section' as the format, did you type it correctly? int bar @section("foo, "); // #error: Mach-o requires 'segment,section' as the format, did you type it correctly?
int baz @section("foo"); // #error: Mach-o requires 'segment,section' as the format, did you type it correctly? int baz @section("foo"); // #error: Mach-o requires 'segment,section' as the format, did you type it correctly?
int abc @section("foo,b,c,d,e,f"); // #error: Too many parts to the Mach-o section description. int abc @section("foo,b,c,d,e,f"); // #error: Too many parts to the Mach-o section description.
int def @section("foo,b,c,d"); int defg @section("foo,b,c,d");

View File

@@ -3,13 +3,13 @@ module test;
bitstruct Foo : int bitstruct Foo : int
{ {
int abc : 0..4; int abc : 0..4;
int def : 23..26; int defg : 23..26;
} }
fn void main() fn void main()
{ {
Foo f; Foo f;
int z = (int) Foo { .abc = 2, .def = 1 }; int z = (int) Foo { .abc = 2, .defg = 1 };
} }
/* #expect: test.ll /* #expect: test.ll

View File

@@ -81,7 +81,7 @@ fn int test(int x) {
} }
extern fn void abc(int *x); extern fn void abc(int *x);
fn int def(int y, int z) { fn int deff(int y, int z) {
abc(&z); abc(&z);
return y; return y;
} }
@@ -234,7 +234,7 @@ entry:
declare void @abc(ptr) #0 declare void @abc(ptr) #0
define i32 @test.def(i32 %0, i32 %1) #0 { define i32 @test.deff(i32 %0, i32 %1) #0 {
entry: entry:
%z = alloca i32, align 4 %z = alloca i32, align 4
store i32 %1, ptr %z, align 4 store i32 %1, ptr %z, align 4

View File

@@ -13,10 +13,10 @@ fn void main()
{ {
var $x = { { 1, 2 } }; var $x = { { 1, 2 } };
Foo[1] abc = (Foo[1])$x; Foo[1] abc = (Foo[1])$x;
Foo def = (Foo)$x[0]; Foo defg = (Foo)$x[0];
int[2][1] y = (int[2][1])$x; int[2][1] y = (int[2][1])$x;
double[2][1] y2 = $x; double[2][1] y2 = $x;
io::printfn("%s %s {%s, %s}", y, y2, def.a, def.b); io::printfn("%s %s {%s, %s}", y, y2, defg.a, defg.b);
test({ 1, 2 }, { 3, 4}, { 5, 6 }); test({ 1, 2 }, { 3, 4}, { 5, 6 });
var $a = { 2, 7 }; var $a = { 2, 7 };
test($a, $a, $a); test($a, $a, $a);
@@ -78,7 +78,7 @@ entry:
define void @test.main() #0 { define void @test.main() #0 {
entry: entry:
%abc = alloca [1 x %Foo], align 4 %abc = alloca [1 x %Foo], align 4
%def = alloca %Foo, align 4 %defg = alloca %Foo, align 4
%y = alloca [1 x [2 x i32]], align 4 %y = alloca [1 x [2 x i32]], align 4
%y2 = alloca [1 x [2 x double]], align 16 %y2 = alloca [1 x [2 x double]], align 16
%retparam = alloca i64, align 8 %retparam = alloca i64, align 8
@@ -90,7 +90,7 @@ entry:
%literal3 = alloca [2 x i32], align 4 %literal3 = alloca [2 x i32], align 4
%taddr4 = alloca <2 x i32>, align 8 %taddr4 = alloca <2 x i32>, align 8
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %abc, ptr align 4 @.__const, i32 8, i1 false) call void @llvm.memcpy.p0.p0.i32(ptr align 4 %abc, ptr align 4 @.__const, i32 8, i1 false)
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %def, ptr align 4 @.__const.1, i32 8, i1 false) call void @llvm.memcpy.p0.p0.i32(ptr align 4 %defg, ptr align 4 @.__const.1, i32 8, i1 false)
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %y, ptr align 4 @.__const.2, i32 8, i1 false) call void @llvm.memcpy.p0.p0.i32(ptr align 4 %y, ptr align 4 @.__const.2, i32 8, i1 false)
call void @llvm.memcpy.p0.p0.i32(ptr align 16 %y2, ptr align 16 @.__const.3, i32 16, i1 false) call void @llvm.memcpy.p0.p0.i32(ptr align 16 %y2, ptr align 16 @.__const.3, i32 16, i1 false)
%0 = insertvalue %any undef, ptr %y, 0 %0 = insertvalue %any undef, ptr %y, 0
@@ -101,12 +101,12 @@ entry:
%4 = insertvalue %any %3, i64 ptrtoint (ptr @"$ct.a1$a2$double" to i64), 1 %4 = insertvalue %any %3, i64 ptrtoint (ptr @"$ct.a1$a2$double" to i64), 1
%5 = getelementptr inbounds [4 x %any], ptr %varargslots, i64 0, i64 1 %5 = getelementptr inbounds [4 x %any], ptr %varargslots, i64 0, i64 1
store %any %4, ptr %5, align 16 store %any %4, ptr %5, align 16
%6 = getelementptr inbounds %Foo, ptr %def, i32 0, i32 0 %6 = getelementptr inbounds %Foo, ptr %defg, i32 0, i32 0
%7 = insertvalue %any undef, ptr %6, 0 %7 = insertvalue %any undef, ptr %6, 0
%8 = insertvalue %any %7, i64 ptrtoint (ptr @"$ct.int" to i64), 1 %8 = insertvalue %any %7, i64 ptrtoint (ptr @"$ct.int" to i64), 1
%9 = getelementptr inbounds [4 x %any], ptr %varargslots, i64 0, i64 2 %9 = getelementptr inbounds [4 x %any], ptr %varargslots, i64 0, i64 2
store %any %8, ptr %9, align 16 store %any %8, ptr %9, align 16
%10 = getelementptr inbounds %Foo, ptr %def, i32 0, i32 1 %10 = getelementptr inbounds %Foo, ptr %defg, i32 0, i32 1
%11 = insertvalue %any undef, ptr %10, 0 %11 = insertvalue %any undef, ptr %10, 0
%12 = insertvalue %any %11, i64 ptrtoint (ptr @"$ct.int" to i64), 1 %12 = insertvalue %any %11, i64 ptrtoint (ptr @"$ct.int" to i64), 1
%13 = getelementptr inbounds [4 x %any], ptr %varargslots, i64 0, i64 3 %13 = getelementptr inbounds [4 x %any], ptr %varargslots, i64 0, i64 3

View File

@@ -28,7 +28,7 @@ entry:
store i8 %ternary, ptr %c, align 1 store i8 %ternary, ptr %c, align 1
%2 = load i32, ptr %b, align 4 %2 = load i32, ptr %b, align 4
%intbool = icmp ne i32 %2, 0 %intbool = icmp ne i32 %2, 0
%ternary1 = select i1 %intbool, i32 %2, i32 1 %elvis = select i1 %intbool, i32 %2, i32 1
store i32 %ternary1, ptr %d, align 4 store i32 %elvis, ptr %d, align 4
ret void ret void
} }