@@ -442,6 +442,103 @@ PseudoCFunction::FieldDisplayType PseudoCFunction::GetFieldDisplayType(
442442 return FieldDisplayNone;
443443}
444444
445+ std::optional<PseudoCFunction::TernaryInfo> PseudoCFunction::CanSimplifyToTernary (const BinaryNinja::HighLevelILInstruction &instr) const
446+ {
447+ // Only handle if-statements
448+ if (instr.operation != HLIL_IF)
449+ return std::nullopt ;
450+
451+ auto conditionExpr = instr.GetConditionExpr <HLIL_IF>();
452+ auto trueExpr = instr.GetTrueExpr <HLIL_IF>();
453+ auto falseExpr = instr.GetFalseExpr <HLIL_IF>();
454+
455+ if (GetHighLevelILFunction ()->HasSideEffects (conditionExpr))
456+ return std::nullopt ;
457+ // Both branches must be assignment operations
458+ if (trueExpr.operation != HLIL_ASSIGN || falseExpr.operation != HLIL_ASSIGN)
459+ return std::nullopt ;
460+
461+ // Get the destination expressions of the assignments
462+ auto trueDestExpr = trueExpr.GetDestExpr <HLIL_ASSIGN>();
463+ auto falseDestExpr = falseExpr.GetDestExpr <HLIL_ASSIGN>();
464+
465+ // Verify that the destination expressions are variable references
466+ if (trueDestExpr.operation != HLIL_VAR || falseDestExpr.operation != HLIL_VAR)
467+ return std::nullopt ;
468+
469+ auto trueExprDestExpr = trueExpr.GetDestExpr <HLIL_ASSIGN>();
470+ auto falseExprDestExpr = falseExpr.GetDestExpr <HLIL_ASSIGN>();
471+ if (trueExprDestExpr.operation != HLIL_VAR || falseExprDestExpr.operation != HLIL_VAR)
472+ return std::nullopt ;
473+
474+ auto trueExprDestVar = trueExprDestExpr.GetVariable <HLIL_VAR>();
475+ auto falseExprDestVar = falseExprDestExpr.GetVariable <HLIL_VAR>();
476+ if (trueExprDestVar != falseExprDestVar)
477+ return std::nullopt ;
478+
479+ auto trueExprSourceExpr = trueExpr.GetSourceExpr <HLIL_ASSIGN>();
480+ auto falseExprSourceExpr = falseExpr.GetSourceExpr <HLIL_ASSIGN>();
481+ if (GetHighLevelILFunction ()->HasSideEffects (trueExprSourceExpr) || GetHighLevelILFunction ()->HasSideEffects (falseExprSourceExpr))
482+ return std::nullopt ;
483+
484+ // Avoid folding for "else if" cases
485+ for (auto parent = instr; parent.HasParent (); parent = parent.GetParent ())
486+ {
487+ if (parent.operation != HLIL_IF)
488+ break ;
489+ auto parentFalse = parent.GetFalseExpr <HLIL_IF>();
490+ if (parentFalse.operation == HLIL_IF)
491+ return std::nullopt ;
492+ }
493+
494+ TernaryInfo info;
495+ info.conditional = conditionExpr;
496+ info.assignDest = trueDestExpr;
497+ info.trueAssign = trueExprSourceExpr;
498+ info.falseAssign = falseExprSourceExpr;
499+ return info;
500+ }
501+
502+ bool PseudoCFunction::TryEmitSimplifiedTernary (
503+ const BinaryNinja::HighLevelILInstruction &instr,
504+ DisassemblySettings* settings,
505+ BinaryNinja::HighLevelILTokenEmitter &emitter
506+ )
507+ {
508+ auto ternaryOpt = CanSimplifyToTernary (instr);
509+ if (!ternaryOpt.has_value ())
510+ return false ;
511+
512+ auto &[conditional, assignDest, trueAssign, falseAssign] = ternaryOpt.value ();
513+
514+ std::vector<InstructionTextToken> tokens = emitter.GetCurrentTokens ();
515+ size_t originalTokenCount = tokens.size ();
516+
517+ // Emit the destination expression
518+ GetExprText (assignDest, emitter, settings, AssignmentOperatorPrecedence);
519+ emitter.Append (OperationToken, " = " );
520+
521+ // Emit the condition expression
522+ GetExprText (conditional, emitter, settings, TernaryOperatorPrecedence);
523+ emitter.Append (OperationToken, " ? " );
524+
525+ // Emit the true-source expression
526+ GetExprText (trueAssign, emitter, settings, TernaryOperatorPrecedence);
527+ emitter.Append (OperationToken, " : " );
528+
529+ // Emit the false-source expression
530+ GetExprText (falseAssign, emitter, settings, TernaryOperatorPrecedence);
531+ emitter.Append (KeywordToken, " ;" );
532+
533+ // If the ternary expression is too complex (i.e. too many tokens), revert back.
534+ if (tokens.size () - originalTokenCount > emitter.GetMaxTernarySimplificationTokens ())
535+ {
536+ tokens.resize (originalTokenCount);
537+ return false ;
538+ }
539+ return true ;
540+ }
541+
445542
446543void PseudoCFunction::AppendDefaultSplitExpr (const BinaryNinja::HighLevelILInstruction& instr,
447544 BinaryNinja::HighLevelILTokenEmitter& tokens, DisassemblySettings* settings, BNOperatorPrecedence precedence)
@@ -672,6 +769,9 @@ void PseudoCFunction::GetExprTextInternal(const HighLevelILInstruction& instr, H
672769 case HLIL_IF:
673770 [&]()
674771 {
772+ if (instr.ast && TryEmitSimplifiedTernary (instr, settings, tokens))
773+ return ;
774+
675775 const auto condExpr = instr.GetConditionExpr <HLIL_IF>();
676776 const auto trueExpr = instr.GetTrueExpr <HLIL_IF>();
677777 const auto falseExpr = instr.GetFalseExpr <HLIL_IF>();
0 commit comments