LLVMValueRef gen_not(compile_t* c, ast_t* ast) { LLVMValueRef value = gen_expr(c, ast); if(value == NULL) return NULL; ast_t* type = ast_type(ast); if(is_bool(type)) { if(LLVMIsAConstantInt(value)) { if(is_always_true(value)) return LLVMConstInt(c->ibool, 0, false); return LLVMConstInt(c->ibool, 1, false); } LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntEQ, value, LLVMConstInt(c->ibool, 0, false), ""); return LLVMBuildZExt(c->builder, test, c->ibool, ""); } if(LLVMIsAConstantInt(value)) return LLVMConstNot(value); return LLVMBuildNot(c->builder, value, ""); }
static bool is_always_false(LLVMValueRef val) { if(!LLVMIsAConstantInt(val)) return false; return LLVMConstIntGetZExtValue(val) == 0; }
static bool is_constant_i1(compile_t* c, LLVMValueRef val) { if(!LLVMIsAConstantInt(val)) return false; LLVMTypeRef type = LLVMTypeOf(val); return type == c->i1; }
LLVMValueRef gen_not(compile_t* c, ast_t* ast) { LLVMValueRef value = gen_expr(c, ast); if(value == NULL) return NULL; if(LLVMIsAConstantInt(value)) return LLVMConstNot(value); return LLVMBuildNot(c->builder, value, ""); }
LLVMValueRef gen_neg(compile_t* c, ast_t* ast) { LLVMValueRef value = gen_expr(c, ast); if(value == NULL) return NULL; if(LLVMIsAConstantFP(value)) return LLVMConstFNeg(value); if(LLVMIsAConstantInt(value)) return LLVMConstNeg(value); if(is_fp(value)) return LLVMBuildFNeg(c->builder, value, ""); return LLVMBuildNeg(c->builder, value, ""); }
LLVMValueRef make_short_circuit(compile_t* c, ast_t* left, ast_t* right, bool is_and) { LLVMBasicBlockRef entry_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef left_block = codegen_block(c, "sc_left"); LLVMValueRef branch = LLVMBuildBr(c->builder, left_block); LLVMPositionBuilderAtEnd(c->builder, left_block); LLVMValueRef l_value = gen_expr(c, left); if(l_value == NULL) return NULL; if(LLVMIsAConstantInt(l_value)) { LLVMInstructionEraseFromParent(branch); LLVMDeleteBasicBlock(left_block); LLVMPositionBuilderAtEnd(c->builder, entry_block); if(is_and) { if(is_always_false(l_value)) return gen_expr(c, left); } else { if(is_always_true(l_value)) return gen_expr(c, left); } return gen_expr(c, right); } LLVMBasicBlockRef left_exit_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef right_block = codegen_block(c, "sc_right"); LLVMBasicBlockRef post_block = codegen_block(c, "sc_post"); LLVMValueRef test = LLVMBuildTrunc(c->builder, l_value, c->i1, ""); if(is_and) LLVMBuildCondBr(c->builder, test, right_block, post_block); else LLVMBuildCondBr(c->builder, test, post_block, right_block); LLVMPositionBuilderAtEnd(c->builder, right_block); LLVMValueRef r_value = gen_expr(c, right); if(r_value == NULL) return NULL; LLVMBasicBlockRef right_exit_block = LLVMGetInsertBlock(c->builder); LLVMBuildBr(c->builder, post_block); LLVMPositionBuilderAtEnd(c->builder, post_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->ibool, ""); LLVMAddIncoming(phi, &l_value, &left_exit_block, 1); LLVMAddIncoming(phi, &r_value, &right_exit_block, 1); if(LLVMIsAConstantInt(r_value)) { if(is_and) { if(is_always_false(r_value)) return r_value; } else { if(is_always_true(r_value)) return r_value; } return l_value; } return phi; }
LLVMValueRef gen_if(compile_t* c, ast_t* ast) { bool needed = is_result_needed(ast); ast_t* type = ast_type(ast); AST_GET_CHILDREN(ast, cond, left, right); ast_t* left_type = ast_type(left); ast_t* right_type = ast_type(right); // We will have no type if both branches have return statements. reach_type_t* phi_type = NULL; if(!is_control_type(type)) phi_type = reach_type(c->reach, type); LLVMValueRef c_value = gen_expr(c, cond); if(c_value == NULL) return NULL; // If the conditional is constant, generate only one branch. bool gen_left = true; bool gen_right = true; if(LLVMIsAConstantInt(c_value)) { int value = (int)LLVMConstIntGetZExtValue(c_value); if(value == 0) gen_left = false; else gen_right = false; } LLVMBasicBlockRef then_block = codegen_block(c, "if_then"); LLVMBasicBlockRef else_block = codegen_block(c, "if_else"); LLVMBasicBlockRef post_block = NULL; // If both branches return, we have no post block. if(!is_control_type(type)) post_block = codegen_block(c, "if_post"); LLVMValueRef test = LLVMBuildTrunc(c->builder, c_value, c->i1, ""); LLVMBuildCondBr(c->builder, test, then_block, else_block); // Left branch. LLVMPositionBuilderAtEnd(c->builder, then_block); LLVMValueRef l_value; if(gen_left) { l_value = gen_expr(c, left); } else if(phi_type != NULL) { l_value = LLVMConstNull(phi_type->use_type); } else { LLVMBuildUnreachable(c->builder); l_value = GEN_NOVALUE; } if(l_value != GEN_NOVALUE) { if(needed) l_value = gen_assign_cast(c, phi_type->use_type, l_value, left_type); if(l_value == NULL) return NULL; then_block = LLVMGetInsertBlock(c->builder); LLVMBuildBr(c->builder, post_block); } // Right branch. LLVMPositionBuilderAtEnd(c->builder, else_block); LLVMValueRef r_value; if(gen_right) { r_value = gen_expr(c, right); } else if(phi_type != NULL) { r_value = LLVMConstNull(phi_type->use_type); } else { LLVMBuildUnreachable(c->builder); r_value = GEN_NOVALUE; } // If the right side returns, we don't branch to the post block. if(r_value != GEN_NOVALUE) { if(needed) r_value = gen_assign_cast(c, phi_type->use_type, r_value, right_type); if(r_value == NULL) return NULL; else_block = LLVMGetInsertBlock(c->builder); LLVMBuildBr(c->builder, post_block); } // If both sides return, we return a sentinal value. if(is_control_type(type)) return GEN_NOVALUE; // Continue in the post block. LLVMPositionBuilderAtEnd(c->builder, post_block); if(needed) { LLVMValueRef phi = LLVMBuildPhi(c->builder, phi_type->use_type, ""); if(l_value != GEN_NOVALUE) LLVMAddIncoming(phi, &l_value, &then_block, 1); if(r_value != GEN_NOVALUE) LLVMAddIncoming(phi, &r_value, &else_block, 1); return phi; } return GEN_NOTNEEDED; }