LLVMValueRef gen_xor(compile_t* c, ast_t* left, ast_t* right) { LLVMValueRef l_value = gen_expr(c, left); LLVMValueRef r_value = gen_expr(c, right); if((l_value == NULL) || (r_value == NULL)) return NULL; if(LLVMIsConstant(l_value) && LLVMIsConstant(r_value)) return LLVMConstXor(l_value, r_value); if(is_always_true(c, l_value)) return LLVMBuildNot(c->builder, r_value, ""); if(is_always_false(c, l_value)) return r_value; if(is_always_true(c, r_value)) return LLVMBuildNot(c->builder, l_value, ""); if(is_always_false(c, r_value)) return l_value; return LLVMBuildXor(c->builder, l_value, r_value, ""); }
LLVMValueRef gen_or(compile_t* c, ast_t* left, ast_t* right) { LLVMValueRef l_value = gen_expr(c, left); LLVMValueRef r_value = gen_expr(c, right); if((l_value == NULL) || (r_value == NULL)) return NULL; if(LLVMIsConstant(l_value) && LLVMIsConstant(r_value)) return LLVMConstOr(l_value, r_value); if(is_always_true(c, l_value) || is_always_true(c, r_value)) return LLVMConstInt(c->i1, 1, false); return LLVMBuildOr(c->builder, l_value, r_value, ""); }
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, ""); }
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(is_constant_i1(c, l_value)) { LLVMInstructionEraseFromParent(branch); LLVMDeleteBasicBlock(left_block); LLVMPositionBuilderAtEnd(c->builder, entry_block); if(is_and) { if(is_always_false(c, l_value)) return gen_expr(c, left); } else { if(is_always_true(c, 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"); if(is_and) LLVMBuildCondBr(c->builder, l_value, right_block, post_block); else LLVMBuildCondBr(c->builder, l_value, 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->i1, ""); LLVMAddIncoming(phi, &l_value, &left_exit_block, 1); LLVMAddIncoming(phi, &r_value, &right_exit_block, 1); if(is_constant_i1(c, r_value)) { if(is_and) { if(is_always_false(c, r_value)) return r_value; } else { if(is_always_true(c, r_value)) return r_value; } return l_value; } return phi; }