diff options
| author | Jeff Garzik <jeff@garzik.org> | 2011-08-27 10:55:04 +0300 |
|---|---|---|
| committer | Pekka Enberg <penberg@kernel.org> | 2011-08-27 11:00:46 +0300 |
| commit | f0f961f3a2d84c368aefadd8e5fc20036bfd110e (patch) | |
| tree | 9b05e5df4d74852cbbcdc6f1ee0f5e3c536c9afb | |
| parent | 6071a81229aee0c44028e379edbe6f7f0e55c6cc (diff) | |
| download | sparse-dev-f0f961f3a2d84c368aefadd8e5fc20036bfd110e.tar.gz | |
sparse, llvm: if-else code generation
It gets the code a bit farther, with the following test case:
int foo(int x)
{
if (x > 0xffff)
x++;
else
x--;
return x;
}
* run with
./sparse-llvm hello.c | llvm-dis
for an IMO more useful disassembly than via 'llc'
* add 'priv' to struct basic_block
* run a first pass through the BB's, creating LLVMBasicBlockRef's and assigning
them to bb->priv
* comment out unssa() call, and implement OP_PHI and OP_PHISOURCE, which LLVM
directly supports.
* remove '%' prefix from PSEUDO_REG names, as it was redundant and made
llvm-dis output ugly
* implement support for conditional and unconditional branches (OP_BR)
* implement OP_COPY. a possibly better implementation would be a single-source
LLVMBuildPhi
[ penberg@kernel.org: minor cleanups ]
Signed-off-by: Pekka Enberg <penberg@kernel.org>
| -rw-r--r-- | linearize.h | 1 | ||||
| -rw-r--r-- | sparse-llvm.c | 98 |
2 files changed, 87 insertions, 12 deletions
diff --git a/linearize.h b/linearize.h index c441c739..424ba970 100644 --- a/linearize.h +++ b/linearize.h @@ -232,6 +232,7 @@ struct basic_block { struct basic_block_list *children; /* destinations */ struct instruction_list *insns; /* Linear list of instructions */ struct pseudo_list *needs, *defines; + void *priv; }; static inline int is_branch_goto(struct instruction *br) diff --git a/sparse-llvm.c b/sparse-llvm.c index c13ab5d2..1697e92f 100644 --- a/sparse-llvm.c +++ b/sparse-llvm.c @@ -71,7 +71,7 @@ static void pseudo_name(pseudo_t pseudo, char *buf) { switch (pseudo->type) { case PSEUDO_REG: - snprintf(buf, MAX_PSEUDO_NAME, "%%r%d", pseudo->nr); + snprintf(buf, MAX_PSEUDO_NAME, "R%d", pseudo->nr); break; case PSEUDO_SYM: assert(0); @@ -84,7 +84,7 @@ static void pseudo_name(pseudo_t pseudo, char *buf) break; } case PSEUDO_PHI: - assert(0); + snprintf(buf, MAX_PSEUDO_NAME, "PHI%d", pseudo->nr); break; default: assert(0); @@ -110,7 +110,7 @@ static LLVMValueRef pseudo_to_value(struct function *fn, pseudo_t pseudo) break; } case PSEUDO_PHI: - assert(0); + result = pseudo->priv; break; default: assert(0); @@ -234,6 +234,20 @@ static void output_op_ret(struct function *fn, struct instruction *insn) LLVMBuildRetVoid(fn->builder); } +static void output_op_br(struct function *fn, struct instruction *br) +{ + if (br->cond) { + LLVMValueRef cond = pseudo_to_value(fn, br->cond); + + LLVMBuildCondBr(fn->builder, cond, + br->bb_true->priv, + br->bb_false->priv); + } else + LLVMBuildBr(fn->builder, + br->bb_true ? br->bb_true->priv : + br->bb_false->priv); +} + static void output_insn(struct function *fn, struct instruction *insn) { switch (insn->opcode) { @@ -241,7 +255,7 @@ static void output_insn(struct function *fn, struct instruction *insn) output_op_ret(fn, insn); break; case OP_BR: - assert(0); + output_op_br(fn, insn); break; case OP_SYMADDR: assert(0); @@ -255,12 +269,45 @@ static void output_insn(struct function *fn, struct instruction *insn) case OP_COMPUTEDGOTO: assert(0); break; - case OP_PHISOURCE: - assert(0); + case OP_PHISOURCE: { + LLVMValueRef src, target; + char target_name[64]; + + pseudo_name(insn->target, target_name); + src = pseudo_to_value(fn, insn->phi_src); + + target = LLVMBuildAdd(fn->builder, src, + LLVMConstInt(LLVMInt32Type(), 0, 0), target_name); + + insn->target->priv = target; break; - case OP_PHI: - assert(0); + } + case OP_PHI: { + pseudo_t phi; + LLVMValueRef target; + + target = LLVMBuildPhi(fn->builder, symbol_type(insn->type), + "phi"); + int pll = 0; + FOR_EACH_PTR(insn->phi_list, phi) { + pll++; + } END_FOR_EACH_PTR(phi); + + LLVMValueRef *phi_vals = calloc(pll, sizeof(LLVMValueRef)); + LLVMBasicBlockRef *phi_blks = calloc(pll, sizeof(LLVMBasicBlockRef)); + + 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++; + } END_FOR_EACH_PTR(phi); + + LLVMAddIncoming(target, phi_vals, phi_blks, pll); + + insn->target->priv = target; break; + } case OP_LOAD: case OP_LNOP: assert(0); break; @@ -320,9 +367,19 @@ static void output_insn(struct function *fn, struct instruction *insn) case OP_ASM: assert(0); break; - case OP_COPY: - assert(0); + case OP_COPY: { + LLVMValueRef src, target; + char target_name[64]; + + pseudo_name(insn->target, target_name); + src = pseudo_to_value(fn, insn->src); + + target = LLVMBuildAdd(fn->builder, src, + LLVMConstInt(LLVMInt32Type(), 0, 0), target_name); + + insn->target->priv = target; break; + } default: break; } @@ -372,21 +429,38 @@ static void output_fn(LLVMModuleRef module, struct entrypoint *ep) function.type = LLVMFunctionType(return_type, arg_types, nr_args, 0); function.fn = LLVMAddFunction(module, name, function.type); + LLVMSetFunctionCallConv(function.fn, LLVMCCallConv); LLVMSetLinkage(function.fn, function_linkage(sym)); +#if 0 unssa(ep); +#endif function.builder = LLVMCreateBuilder(); - LLVMBasicBlockRef entry = LLVMAppendBasicBlock(function.fn, "entry"); + static int nr_bb; + + FOR_EACH_PTR(ep->bbs, bb) { + if (bb->generation == generation) + continue; - LLVMPositionBuilderAtEnd(function.builder, entry); + LLVMBasicBlockRef bbr; + char bbname[32]; + + sprintf(bbname, "L%d", nr_bb++); + bbr = LLVMAppendBasicBlock(function.fn, bbname); + + bb->priv = bbr; + } + END_FOR_EACH_PTR(bb); FOR_EACH_PTR(ep->bbs, bb) { if (bb->generation == generation) continue; + LLVMPositionBuilderAtEnd(function.builder, bb->priv); + output_bb(&function, bb, generation); } END_FOR_EACH_PTR(bb); |
