diff options
| author | Jeff Garzik <jeff@garzik.org> | 2011-08-27 02:18:17 -0400 |
|---|---|---|
| committer | Pekka Enberg <penberg@kernel.org> | 2011-08-27 11:06:15 +0300 |
| commit | 9e2fce867f280cca89a91e1409af9389717f4716 (patch) | |
| tree | 9dd56dbf3b8bac40a317fa6e890c5f7b07727ed0 | |
| parent | 5c6931812fc1ad2893f7c35005b3dbdaab25c73f (diff) | |
| download | sparse-dev-9e2fce867f280cca89a91e1409af9389717f4716.tar.gz | |
sparse-llvm: OP_SWITCH
testcase:
int foo(int x)
{
switch (x) {
case 1:
return 11;
case 2:
return 22;
default:
return 33;
}
return 44;
}
Signed-off-by: Pekka Enberg <penberg@kernel.org>
| -rw-r--r-- | sparse-llvm.c | 52 |
1 files changed, 47 insertions, 5 deletions
diff --git a/sparse-llvm.c b/sparse-llvm.c index 810797ca..c6575b18 100644 --- a/sparse-llvm.c +++ b/sparse-llvm.c @@ -112,6 +112,9 @@ static LLVMValueRef pseudo_to_value(struct function *fn, pseudo_t pseudo) case PSEUDO_PHI: result = pseudo->priv; break; + case PSEUDO_VOID: + result = NULL; + break; default: assert(0); } @@ -261,6 +264,39 @@ static void output_op_sel(struct function *fn, struct instruction *insn) insn->target->priv = target; } +static void output_op_switch(struct function *fn, struct instruction *insn) +{ + LLVMValueRef sw_val, target; + struct basic_block *def = NULL; + struct multijmp *jmp; + int n_jmp = 0; + + FOR_EACH_PTR(insn->multijmp_list, jmp) { + if (jmp->begin == jmp->end) { /* case N */ + n_jmp++; + } else if (jmp->begin < jmp->end) { /* case M..N */ + /* FIXME */ + } else /* default case */ + def = jmp->target; + } END_FOR_EACH_PTR(jmp); + + sw_val = pseudo_to_value(fn, insn->target); + target = LLVMBuildSwitch(fn->builder, sw_val, + def ? def->priv : NULL, n_jmp); + + FOR_EACH_PTR(insn->multijmp_list, jmp) { + if (jmp->begin == jmp->end) { /* case N */ + LLVMAddCase(target, + LLVMConstInt(LLVMInt32Type(), jmp->begin, 0), + jmp->target->priv); + } else if (jmp->begin < jmp->end) { /* case M..N */ + /* FIXME */ + } + } END_FOR_EACH_PTR(jmp); + + insn->target->priv = target; +} + static void output_insn(struct function *fn, struct instruction *insn) { switch (insn->opcode) { @@ -277,7 +313,7 @@ static void output_insn(struct function *fn, struct instruction *insn) assert(0); break; case OP_SWITCH: - assert(0); + output_op_switch(fn, insn); break; case OP_COMPUTEDGOTO: assert(0); @@ -303,7 +339,8 @@ static void output_insn(struct function *fn, struct instruction *insn) "phi"); int pll = 0; FOR_EACH_PTR(insn->phi_list, phi) { - pll++; + if (pseudo_to_value(fn, phi)) /* skip VOID */ + pll++; } END_FOR_EACH_PTR(phi); LLVMValueRef *phi_vals = calloc(pll, sizeof(LLVMValueRef)); @@ -311,9 +348,14 @@ static void output_insn(struct function *fn, struct instruction *insn) int idx = 0; FOR_EACH_PTR(insn->phi_list, phi) { - phi_vals[idx] = pseudo_to_value(fn, phi); - phi_blks[idx] = phi->def->bb->priv; - idx++; + LLVMValueRef v; + + v = pseudo_to_value(fn, phi); + if (v) { /* skip VOID */ + phi_vals[idx] = v; + phi_blks[idx] = phi->def->bb->priv; + idx++; + } } END_FOR_EACH_PTR(phi); LLVMAddIncoming(target, phi_vals, phi_blks, pll); |
