@@ -442,6 +442,103 @@ PseudoCFunction::FieldDisplayType PseudoCFunction::GetFieldDisplayType(
442
442
return FieldDisplayNone;
443
443
}
444
444
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
+
445
542
446
543
void PseudoCFunction::AppendDefaultSplitExpr (const BinaryNinja::HighLevelILInstruction& instr,
447
544
BinaryNinja::HighLevelILTokenEmitter& tokens, DisassemblySettings* settings, BNOperatorPrecedence precedence)
@@ -672,6 +769,9 @@ void PseudoCFunction::GetExprTextInternal(const HighLevelILInstruction& instr, H
672
769
case HLIL_IF:
673
770
[&]()
674
771
{
772
+ if (instr.ast && TryEmitSimplifiedTernary (instr, settings, tokens))
773
+ return ;
774
+
675
775
const auto condExpr = instr.GetConditionExpr <HLIL_IF>();
676
776
const auto trueExpr = instr.GetTrueExpr <HLIL_IF>();
677
777
const auto falseExpr = instr.GetFalseExpr <HLIL_IF>();
0 commit comments