+
+
+/*
+ Example of if/then/else building:
+
+ int x;
+ if (cond) {
+ x = 1 + 2;
+ }
+ else {
+ x = 2 + 3;
+ }
+
+ Is built with:
+
+ LLVMValueRef x = LLVMGetUndef(); // or something else
+
+ flow = lp_build_flow_create(builder);
+
+ lp_build_flow_scope_begin(flow);
+
+ // x needs a phi node
+ lp_build_flow_scope_declare(flow, &x);
+
+ lp_build_if(ctx, flow, builder, cond);
+ x = LLVMAdd(1, 2);
+ lp_build_else(ctx);
+ x = LLVMAdd(2, 3);
+ lp_build_endif(ctx);
+
+ lp_build_flow_scope_end(flow);
+
+ lp_build_flow_destroy(flow);
+ */
+
+
+
+/**
+ * Begin an if/else/endif construct.
+ */
+void
+lp_build_if(struct lp_build_if_state *ctx,
+ struct lp_build_flow_context *flow,
+ LLVMBuilderRef builder,
+ LLVMValueRef condition)
+{
+ LLVMBasicBlockRef block = LLVMGetInsertBlock(builder);
+ struct lp_build_flow_if *ifthen;
+ unsigned i;
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->builder = builder;
+ ctx->flow = flow;
+
+ /* push/create new scope */
+ ifthen = &lp_build_flow_push(flow, LP_BUILD_FLOW_IF)->ifthen;
+ assert(ifthen);
+
+ ifthen->num_variables = flow->num_variables;
+ ifthen->condition = condition;
+ ifthen->entry_block = block;
+
+ /* create a Phi node for each variable in this flow scope */
+ ifthen->phi = MALLOC(ifthen->num_variables * sizeof(*ifthen->phi));
+ if (!ifthen->phi) {
+ ifthen->num_variables = 0;
+ return;
+ }
+
+ /* create endif/merge basic block for the phi functions */
+ ifthen->merge_block = lp_build_insert_new_block(builder, "endif-block");
+ LLVMPositionBuilderAtEnd(builder, ifthen->merge_block);
+
+ /* create a phi node for each variable */
+ for (i = 0; i < flow->num_variables; i++) {
+ ifthen->phi[i] = LLVMBuildPhi(builder, LLVMTypeOf(*flow->variables[i]), "");
+
+ /* add add the initial value of the var from the entry block */
+ LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->entry_block, 1);
+ }
+
+ /* create/insert true_block before merge_block */
+ ifthen->true_block = LLVMInsertBasicBlock(ifthen->merge_block, "if-true-block");
+
+ /* successive code goes into the true block */
+ LLVMPositionBuilderAtEnd(builder, ifthen->true_block);
+}
+
+
+/**
+ * Begin else-part of a conditional
+ */
+void
+lp_build_else(struct lp_build_if_state *ctx)
+{
+ struct lp_build_flow_context *flow = ctx->flow;
+ struct lp_build_flow_if *ifthen;
+ unsigned i;
+
+ ifthen = &lp_build_flow_peek(flow, LP_BUILD_FLOW_IF)->ifthen;
+ assert(ifthen);
+
+ /* for each variable, update the Phi node with a (variable, block) pair */
+ LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
+ for (i = 0; i < flow->num_variables; i++) {
+ assert(*flow->variables[i]);
+ LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->true_block, 1);
+ }
+
+ /* create/insert false_block before the merge block */
+ ifthen->false_block = LLVMInsertBasicBlock(ifthen->merge_block, "if-false-block");
+
+ /* successive code goes into the else block */
+ LLVMPositionBuilderAtEnd(ctx->builder, ifthen->false_block);
+}
+
+
+/**
+ * End a conditional.
+ */
+void
+lp_build_endif(struct lp_build_if_state *ctx)
+{
+ struct lp_build_flow_context *flow = ctx->flow;
+ struct lp_build_flow_if *ifthen;
+ unsigned i;
+
+ ifthen = &lp_build_flow_pop(flow, LP_BUILD_FLOW_IF)->ifthen;
+ assert(ifthen);
+
+ if (ifthen->false_block) {
+ LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
+ /* for each variable, update the Phi node with a (variable, block) pair */
+ for (i = 0; i < flow->num_variables; i++) {
+ assert(*flow->variables[i]);
+ LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->false_block, 1);
+
+ /* replace the variable ref with the phi function */
+ *flow->variables[i] = ifthen->phi[i];
+ }
+ }
+ else {
+ /* no else clause */
+ LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
+ for (i = 0; i < flow->num_variables; i++) {
+ assert(*flow->variables[i]);
+ LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->true_block, 1);
+
+ /* replace the variable ref with the phi function */
+ *flow->variables[i] = ifthen->phi[i];
+ }
+ }
+
+ FREE(ifthen->phi);
+
+ /***
+ *** Now patch in the various branch instructions.
+ ***/
+
+ /* Insert the conditional branch instruction at the end of entry_block */
+ LLVMPositionBuilderAtEnd(ctx->builder, ifthen->entry_block);
+ if (ifthen->false_block) {
+ /* we have an else clause */
+ LLVMBuildCondBr(ctx->builder, ifthen->condition,
+ ifthen->true_block, ifthen->false_block);
+ }
+ else {
+ /* no else clause */
+ LLVMBuildCondBr(ctx->builder, ifthen->condition,
+ ifthen->true_block, ifthen->merge_block);
+ }
+
+ /* Append an unconditional Br(anch) instruction on the true_block */
+ LLVMPositionBuilderAtEnd(ctx->builder, ifthen->true_block);
+ LLVMBuildBr(ctx->builder, ifthen->merge_block);
+ if (ifthen->false_block) {
+ /* Append an unconditional Br(anch) instruction on the false_block */
+ LLVMPositionBuilderAtEnd(ctx->builder, ifthen->false_block);
+ LLVMBuildBr(ctx->builder, ifthen->merge_block);
+ }
+
+
+ /* Resume building code at end of the ifthen->merge_block */
+ LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
+}