@@ -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 (TextToken, " ;" );
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