aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-22 15:15:20 +0000
committer_ov4 <ov4@ov4.org>2026-10-22 15:21:14 +0000
commit5a5a14be5e2683a42906da4b2ad19690e230c871 (patch)
tree2b039a41a7ffe9ed193f88218e94d324c9fa43fd /lib/CodeGen
parent64622b737f070b377fdef3fb31a67c084457bd7b (diff)
feat(codegen): short-circuit AND and OR
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen')
-rw-r--r--lib/CodeGen/ExpressionGen.cc43
1 files changed, 43 insertions, 0 deletions
diff --git a/lib/CodeGen/ExpressionGen.cc b/lib/CodeGen/ExpressionGen.cc
index 51d7087..45583d3 100644
--- a/lib/CodeGen/ExpressionGen.cc
+++ b/lib/CodeGen/ExpressionGen.cc
@@ -145,6 +145,9 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
if (Overload.Signature)
return emitOperatorCall(*Overload.Signature, Bin->getLHS(), Bin->getRHS());
}
+ if ((Bin->getOp() == tok_and || Bin->getOp() == tok_or) && LT && RT &&
+ Builder->GetInsertBlock() && isLogicalOperand(LT) && isLogicalOperand(RT))
+ return emitShortCircuit(Bin, LT, RT);
Value *L = emitExpr(Bin->getLHS());
Value *R = emitExpr(Bin->getRHS());
return emitBinaryOp(Bin->getOp(), L, LT, R, RT, Bin->getLine());
@@ -173,6 +176,46 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
return nullptr;
}
+// BOOLEAN, or a C scalar tested against zero; everything else keeps the
+// ordinary operator path (and its diagnostics).
+bool CodeGen::isLogicalOperand(const TypeInfo *T) {
+ return T->Kind == TypeKind::Boolean || (T->Kind == TypeKind::CScalar && !T->isVoid());
+}
+
+// AND / OR evaluate the right operand only when the left one does not
+// already decide the result.
+Value *CodeGen::emitShortCircuit(BinaryExprAST *Bin, const TypeInfo *LT, const TypeInfo *RT) {
+ SaveAndRestore<int> Location(DiagnosticLine, Bin->getLine() ? Bin->getLine() : DiagnosticLine);
+ const TypeInfo *Bool = resolveType("BOOLEAN");
+ bool IsAnd = Bin->getOp() == tok_and;
+ auto EmitOperand = [&](ExprAST *E, const TypeInfo *T) -> Value * {
+ Value *V = emitExpr(E);
+ if (!V) return nullptr;
+ return T->Kind == TypeKind::Boolean ? V : convertNumericValue(V, T, Bool);
+ };
+
+ Value *L = EmitOperand(Bin->getLHS(), LT);
+ if (!L) return nullptr;
+ Function *TheFunction = Builder->GetInsertBlock()->getParent();
+ BasicBlock *LeftBB = Builder->GetInsertBlock();
+ BasicBlock *RightBB = BasicBlock::Create(*TheContext, IsAnd ? "and_rhs" : "or_rhs", TheFunction);
+ BasicBlock *DoneBB = BasicBlock::Create(*TheContext, IsAnd ? "and_done" : "or_done", TheFunction);
+ if (IsAnd) Builder->CreateCondBr(L, RightBB, DoneBB);
+ else Builder->CreateCondBr(L, DoneBB, RightBB);
+
+ Builder->SetInsertPoint(RightBB);
+ Value *R = EmitOperand(Bin->getRHS(), RT);
+ if (!R) return nullptr;
+ BasicBlock *RightEndBB = Builder->GetInsertBlock();
+ Builder->CreateBr(DoneBB);
+
+ Builder->SetInsertPoint(DoneBB);
+ PHINode *Result = Builder->CreatePHI(Type::getInt1Ty(*TheContext), 2, IsAnd ? "andtmp" : "ortmp");
+ Result->addIncoming(ConstantInt::get(Type::getInt1Ty(*TheContext), IsAnd ? 0 : 1), LeftBB);
+ Result->addIncoming(R, RightEndBB);
+ return Result;
+}
+
// Ordinary binary expressions and CASE use the same typed operations.
Value *CodeGen::emitBinaryOp(int Op, Value *L, const TypeInfo *LT,
Value *R, const TypeInfo *RT, int Line) {