diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-22 15:15:20 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-22 15:21:14 +0000 |
| commit | 5a5a14be5e2683a42906da4b2ad19690e230c871 (patch) | |
| tree | 2b039a41a7ffe9ed193f88218e94d324c9fa43fd /lib/CodeGen | |
| parent | 64622b737f070b377fdef3fb31a67c084457bd7b (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.cc | 43 |
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) { |
