Skip to content

Commit e97f6d7

Browse files
committed
Add support for alloca() blocks
1 parent ad2a522 commit e97f6d7

21 files changed

+813
-1
lines changed

Diff for: TODO

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
? BSTART, BEND nodes (to free data allocated by ALLOCA) (now it's possible to do this through AFREE)
21
- Full support for function prototypes ???
32
(now we may only set "fastcall" calling convention for constants or for variables through BITCAST)
43

Diff for: ir.c

+7
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ void ir_print_const(const ir_ctx *ctx, const ir_insn *insn, FILE *f, bool quoted
267267
#define ir_op_flag_x2 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
268268
#define ir_op_flag_x3 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
269269
#define ir_op_flag_xN (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | IR_OP_FLAG_VAR_INPUTS)
270+
#define ir_op_flag_a1 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_ALLOC | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
270271
#define ir_op_flag_a2 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_ALLOC | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
271272

272273
#define ir_op_kind____ IR_OPND_UNUSED
@@ -2771,3 +2772,9 @@ ir_ref _ir_VA_ARG(ir_ctx *ctx, ir_type type, ir_ref list)
27712772
IR_ASSERT(ctx->control);
27722773
return ctx->control = ir_emit2(ctx, IR_OPT(IR_VA_ARG, type), ctx->control, list);
27732774
}
2775+
2776+
ir_ref _ir_BLOCK_BEGIN(ir_ctx *ctx)
2777+
{
2778+
IR_ASSERT(ctx->control);
2779+
return ctx->control = ir_emit1(ctx, IR_OPT(IR_BLOCK_BEGIN, IR_ADDR), ctx->control);
2780+
}

Diff for: ir.h

+2
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,8 @@ typedef enum _ir_type {
316316
/* memory reference and load/store ops */ \
317317
_(ALLOCA, a2, src, def, ___) /* alloca(def) */ \
318318
_(AFREE, a2, src, def, ___) /* revert alloca(def) */ \
319+
_(BLOCK_BEGIN, a1, src, ___, ___) /* stacksave */ \
320+
_(BLOCK_END, a2, src, def, ___) /* stackrestore */ \
319321
_(VADDR, d1, var, ___, ___) /* load address of local var */ \
320322
_(VLOAD, l2, src, var, ___) /* load value of local var */ \
321323
_(VSTORE, s3, src, var, def) /* store value to local var */ \

Diff for: ir_aarch64.dasc

+34
Original file line numberDiff line numberDiff line change
@@ -4063,6 +4063,34 @@ static void ir_emit_afree(ir_ctx *ctx, ir_ref def, ir_insn *insn)
40634063
}
40644064
}
40654065

4066+
static void ir_emit_block_begin(ir_ctx *ctx, ir_ref def, ir_insn *insn)
4067+
{
4068+
ir_backend_data *data = ctx->data;
4069+
dasm_State **Dst = &data->dasm_state;
4070+
ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]);
4071+
4072+
| mov Rx(def_reg), sp
4073+
4074+
if (IR_REG_SPILLED(ctx->regs[def][0])) {
4075+
ir_emit_store(ctx, IR_ADDR, def, def_reg);
4076+
}
4077+
}
4078+
4079+
static void ir_emit_block_end(ir_ctx *ctx, ir_ref def, ir_insn *insn)
4080+
{
4081+
ir_backend_data *data = ctx->data;
4082+
dasm_State **Dst = &data->dasm_state;
4083+
ir_reg op2_reg = ctx->regs[def][2];
4084+
4085+
IR_ASSERT(op2_reg != IR_REG_NONE);
4086+
if (IR_REG_SPILLED(op2_reg)) {
4087+
op2_reg = IR_REG_NUM(op2_reg);
4088+
ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2);
4089+
}
4090+
4091+
| mov sp, Rx(op2_reg)
4092+
}
4093+
40664094
static void ir_emit_frame_addr(ir_ctx *ctx, ir_ref def)
40674095
{
40684096
ir_backend_data *data = ctx->data;
@@ -5965,6 +5993,12 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
59655993
case IR_AFREE:
59665994
ir_emit_afree(ctx, i, insn);
59675995
break;
5996+
case IR_BLOCK_BEGIN:
5997+
ir_emit_block_begin(ctx, i, insn);
5998+
break;
5999+
case IR_BLOCK_END:
6000+
ir_emit_block_end(ctx, i, insn);
6001+
break;
59686002
case IR_FRAME_ADDR:
59696003
ir_emit_frame_addr(ctx, i);
59706004
break;

Diff for: ir_builder.h

+4
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,9 @@ extern "C" {
577577

578578
#define ir_FRAME_ADDR() ir_fold0(_ir_CTX, IR_OPT(IR_FRAME_ADDR, IR_ADDR))
579579

580+
#define ir_BLOCK_BEGIN() _ir_BLOCK_BEGIN(_ir_CTX)
581+
#define ir_BLOCK_END(_val) do {_ir_CTX->control = ir_emit2(_ir_CTX, IR_BLOCK_END, _ir_CTX->control, (_val));} while (0)
582+
580583
#define ir_VA_START(_list) _ir_VA_START(_ir_CTX, _list)
581584
#define ir_VA_END(_list) _ir_VA_END(_ir_CTX, _list)
582585
#define ir_VA_COPY(_dst, _src) _ir_VA_COPY(_ir_CTX, _dst, _src)
@@ -680,6 +683,7 @@ void _ir_RETURN(ir_ctx *ctx, ir_ref val);
680683
void _ir_IJMP(ir_ctx *ctx, ir_ref addr);
681684
void _ir_GUARD(ir_ctx *ctx, ir_ref condition, ir_ref addr);
682685
void _ir_GUARD_NOT(ir_ctx *ctx, ir_ref condition, ir_ref addr);
686+
ir_ref _ir_BLOCK_BEGIN(ir_ctx *ctx);
683687
ir_ref _ir_SNAPSHOT(ir_ctx *ctx, ir_ref n);
684688
void _ir_SNAPSHOT_SET_OP(ir_ctx *ctx, ir_ref snapshot, ir_ref pos, ir_ref val);
685689
ir_ref _ir_EXITCALL(ir_ctx *ctx, ir_ref func);

Diff for: ir_emit_c.c

+6
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,12 @@ static int ir_emit_func(ir_ctx *ctx, const char *name, FILE *f)
10371037
case IR_STORE:
10381038
ir_emit_store(ctx, f, insn);
10391039
break;
1040+
case IR_BLOCK_BEGIN:
1041+
fprintf(f, "{\n");
1042+
break;
1043+
case IR_BLOCK_END:
1044+
fprintf(f, "}\n");
1045+
break;
10401046
case IR_FRAME_ADDR:
10411047
ir_emit_def_ref(ctx, f, i);
10421048
fprintf(f, "__builtin_frame_address(0);");

Diff for: ir_emit_llvm.c

+13
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ static const char *ir_type_llvm_name[IR_LAST_LLVM_TYPE] = {
104104
_(MEMCPY, IR_LLVM_MEMCPY_NAME, VOID, 4, PTR, PTR, SSIZE_T, I1) \
105105
_(MEMMOVE, IR_LLVM_MEMMOVE_NAME, VOID, 4, PTR, PTR, SSIZE_T, I1) \
106106
_(FRAMEADDRESS, "llvm.frameaddress.p0", PTR, 1, I32, ___, ___, ___) \
107+
_(STACKSAVE, "llvm.stacksave", PTR, 0, ___, ___, ___, ___) \
108+
_(STACKRESTORE, "llvm.stackrestore", VOID, 1, PTR, ___, ___, ___) \
107109
_(VA_START, "llvm.va_start", VOID, 1, PTR, ___, ___, ___) \
108110
_(VA_END, "llvm.va_end", VOID, 1, PTR, ___, ___, ___) \
109111
_(VA_COPY, "llvm.va_copy", VOID, 2, PTR, PTR, ___, ___) \
@@ -1158,6 +1160,17 @@ static int ir_emit_func(ir_ctx *ctx, const char *name, FILE *f)
11581160
case IR_VSTORE:
11591161
ir_emit_store(ctx, f, insn);
11601162
break;
1163+
case IR_BLOCK_BEGIN:
1164+
ir_emit_def_ref(ctx, f, i);
1165+
ir_bitset_incl(used_intrinsics, IR_LLVM_INTR_STACKSAVE);
1166+
fprintf(f, "\tcall ptr @llvm.stacksave()\n");
1167+
break;
1168+
case IR_BLOCK_END:
1169+
ir_bitset_incl(used_intrinsics, IR_LLVM_INTR_STACKRESTORE);
1170+
fprintf(f, "\tcall void @llvm.stackrestore(ptr ");
1171+
ir_emit_ref(ctx, f, insn->op2);
1172+
fprintf(f, ")\n");
1173+
break;
11611174
case IR_FRAME_ADDR:
11621175
ir_emit_def_ref(ctx, f, i);
11631176
ir_bitset_incl(used_intrinsics, IR_LLVM_INTR_FRAMEADDRESS);

Diff for: ir_load_llvm.c

+7
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,13 @@ static ir_ref llvm2ir_intrinsic(ir_ctx *ctx, LLVMValueRef insn, LLVMTypeRef ftyp
917917
IR_ASSERT(LLVMGetValueKind(LLVMGetOperand(insn, 0)) == LLVMConstantIntValueKind);
918918
IR_ASSERT(LLVMConstIntGetSExtValue(LLVMGetOperand(insn, 0)) == 0);
919919
return ir_FRAME_ADDR();
920+
} else if (STR_EQUAL(name, name_len, "llvm.stacksave")) {
921+
IR_ASSERT(count == 0);
922+
return ir_BLOCK_BEGIN();
923+
} else if (STR_EQUAL(name, name_len, "llvm.stackrestore")) {
924+
IR_ASSERT(count == 1);
925+
ir_BLOCK_END(llvm2ir_op(ctx, LLVMGetOperand(insn, 0), IR_ADDR));
926+
return ctx->control;
920927
} else if (STR_EQUAL(name, name_len, "llvm.debugtrap")) {
921928
ir_TRAP();
922929
return ctx->control;

Diff for: ir_x86.dasc

+34
Original file line numberDiff line numberDiff line change
@@ -7733,6 +7733,34 @@ static void ir_emit_afree(ir_ctx *ctx, ir_ref def, ir_insn *insn)
77337733
}
77347734
}
77357735

7736+
static void ir_emit_block_begin(ir_ctx *ctx, ir_ref def, ir_insn *insn)
7737+
{
7738+
ir_backend_data *data = ctx->data;
7739+
dasm_State **Dst = &data->dasm_state;
7740+
ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]);
7741+
7742+
| mov Ra(def_reg), Ra(IR_REG_RSP)
7743+
7744+
if (IR_REG_SPILLED(ctx->regs[def][0])) {
7745+
ir_emit_store(ctx, IR_ADDR, def, def_reg);
7746+
}
7747+
}
7748+
7749+
static void ir_emit_block_end(ir_ctx *ctx, ir_ref def, ir_insn *insn)
7750+
{
7751+
ir_backend_data *data = ctx->data;
7752+
dasm_State **Dst = &data->dasm_state;
7753+
ir_reg op2_reg = ctx->regs[def][2];
7754+
7755+
IR_ASSERT(op2_reg != IR_REG_NONE);
7756+
if (IR_REG_SPILLED(op2_reg)) {
7757+
op2_reg = IR_REG_NUM(op2_reg);
7758+
ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2);
7759+
}
7760+
7761+
| mov Ra(IR_REG_RSP), Ra(op2_reg)
7762+
}
7763+
77367764
static void ir_emit_frame_addr(ir_ctx *ctx, ir_ref def)
77377765
{
77387766
ir_backend_data *data = ctx->data;
@@ -10391,6 +10419,12 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
1039110419
case IR_AFREE:
1039210420
ir_emit_afree(ctx, i, insn);
1039310421
break;
10422+
case IR_BLOCK_BEGIN:
10423+
ir_emit_block_begin(ctx, i, insn);
10424+
break;
10425+
case IR_BLOCK_END:
10426+
ir_emit_block_end(ctx, i, insn);
10427+
break;
1039410428
case IR_FRAME_ADDR:
1039510429
ir_emit_frame_addr(ctx, i);
1039610430
break;

Diff for: tests/Windows-x86_64/alloca_003.irt

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
003: BLOCK_BEGIN/BLOCK_END
3+
--TARGET--
4+
Windows-x86_64
5+
--ARGS--
6+
-S
7+
--CODE--
8+
func test(int32_t, uintptr_t): void
9+
{
10+
uintptr_t c_1 = 0;
11+
bool c_2 = 0;
12+
bool c_3 = 1;
13+
int32_t c_4 = 4;
14+
int32_t c_5 = 1;
15+
int32_t c_6 = 0;
16+
l_1 = START(l_12);
17+
int32_t d_2 = PARAM(l_1, "arg_1", 1);
18+
uintptr_t d_3 = PARAM(l_1, "arg_2", 2);
19+
int32_t d_4 = MUL(d_2, c_4);
20+
l_5 = END(l_1);
21+
l_6 = LOOP_BEGIN(l_5, l_20);
22+
int32_t d_7 = PHI(l_6, c_6, d_19);
23+
int32_t d_8 = PHI(l_6, c_6, d_17);
24+
bool d_9 = LT(d_7, d_2);
25+
l_10 = IF(l_6, d_9);
26+
l_11 = IF_FALSE(l_10);
27+
l_12 = RETURN(l_11, null);
28+
l_13 = IF_TRUE(l_10);
29+
uintptr_t d_14, l_14 = BLOCK_BEGIN(l_13);
30+
uintptr_t d_15, l_15 = ALLOCA(l_14, d_4);
31+
int32_t d_16, l_16 = CALL/1(l_15, d_3, d_15);
32+
int32_t d_17 = ADD(d_16, d_8);
33+
l_18 = BLOCK_END(l_16, d_14);
34+
int32_t d_19 = ADD(d_7, c_5);
35+
l_20 = LOOP_END(l_18);
36+
}
37+
--EXPECT--

Diff for: tests/aarch64/alloca_003.irt

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
--TEST--
2+
003: BLOCK_BEGIN/BLOCK_END
3+
--TARGET--
4+
aarch64
5+
--ARGS--
6+
-S
7+
--CODE--
8+
func test(int32_t, uintptr_t): void
9+
{
10+
uintptr_t c_1 = 0;
11+
bool c_2 = 0;
12+
bool c_3 = 1;
13+
int32_t c_4 = 4;
14+
uintptr_t c_5 = 0x4;
15+
int32_t c_6 = 1;
16+
int32_t c_7 = 0;
17+
l_1 = START(l_12);
18+
int32_t d_2 = PARAM(l_1, "arg_1", 1);
19+
uintptr_t d_3 = PARAM(l_1, "arg_2", 2);
20+
int32_t d_4 = MUL(d_2, c_4);
21+
l_5 = END(l_1);
22+
l_6 = LOOP_BEGIN(l_5, l_24);
23+
int32_t d_7 = PHI(l_6, c_7, d_23);
24+
int32_t d_8 = PHI(l_6, c_7, d_21);
25+
bool d_9 = LT(d_7, d_2);
26+
l_10 = IF(l_6, d_9);
27+
l_11 = IF_FALSE(l_10);
28+
l_12 = RETURN(l_11, null);
29+
l_13 = IF_TRUE(l_10);
30+
uintptr_t d_14, l_14 = BLOCK_BEGIN(l_13);
31+
uintptr_t d_15, l_15 = ALLOCA(l_14, d_4);
32+
int32_t d_16, l_16 = CALL/1(l_15, d_3, d_15);
33+
int64_t d_17 = SEXT(d_16);
34+
uintptr_t d_18 = MUL(d_17, c_5);
35+
uintptr_t d_19 = ADD(d_18, d_15);
36+
int32_t d_20, l_20 = LOAD(l_16, d_19);
37+
int32_t d_21 = ADD(d_20, d_8);
38+
l_22 = BLOCK_END(l_20, d_14);
39+
int32_t d_23 = ADD(d_7, c_6);
40+
l_24 = LOOP_END(l_22);
41+
}
42+
--EXPECT--
43+
test:
44+
stp x29, x30, [sp, #-0x50]!
45+
mov x29, sp
46+
stp x19, x20, [x29, #0x40]
47+
stp x21, x22, [x29, #0x30]
48+
stp x23, x24, [x29, #0x20]
49+
str x25, [x29, #0x18]
50+
mov w19, w0
51+
mov x20, x1
52+
lsl w21, w19, #2
53+
mov w22, wzr
54+
mov w23, wzr
55+
b .L2
56+
.L1:
57+
mov x24, sp
58+
add x25, x21, #0xf
59+
and x25, x25, #0xfffffffffffffff0
60+
sub sp, sp, x25
61+
mov x25, sp
62+
mov x0, x25
63+
blr x20
64+
sxtw x0, w0
65+
lsl x0, x0, #2
66+
add x0, x0, x25
67+
ldr w0, [x0]
68+
add w22, w0, w22
69+
mov sp, x24
70+
add w23, w23, #1
71+
.L2:
72+
cmp w23, w19
73+
b.lt .L1
74+
ldp x19, x20, [x29, #0x40]
75+
ldp x21, x22, [x29, #0x30]
76+
ldp x23, x24, [x29, #0x20]
77+
ldr x25, [x29, #0x18]
78+
mov sp, x29
79+
ldp x29, x30, [sp], #0x50
80+
ret

Diff for: tests/c/alloca_001.irt

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
001: alloca function
3+
--ARGS--
4+
--emit-c
5+
--CODE--
6+
{
7+
int32_t size = 10;
8+
l_1 = START(l_4);
9+
uintptr_t ret, l_2 = ALLOCA(l_1, size);
10+
l_4 = RETURN(l_2, ret);
11+
}
12+
--EXPECT--
13+
uintptr_t test(void)
14+
{
15+
uintptr_t d_1;
16+
d_1 = (uintptr_t)alloca(10);
17+
return d_1;
18+
}

Diff for: tests/c/alloca_002.irt

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
002: alloca function
3+
--ARGS--
4+
--emit-c
5+
--CODE--
6+
{
7+
l_1 = START(l_4);
8+
int32_t x = PARAM(l_1, "x", 1);
9+
uintptr_t ret, l_2 = ALLOCA(l_1, x);
10+
l_4 = RETURN(l_2, ret);
11+
}
12+
--EXPECT--
13+
uintptr_t test(int32_t x)
14+
{
15+
int32_t d_1 = x;
16+
uintptr_t d_2;
17+
d_2 = (uintptr_t)alloca(d_1);
18+
return d_2;
19+
}

0 commit comments

Comments
 (0)