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