| 347 | } |
| 348 | |
| 349 | void N64Recomp::CGenerator::get_binary_expr_string(BinaryOpType type, const BinaryOperands& operands, const InstructionContext& ctx, const std::string& output, std::string& expr_string) const { |
| 350 | thread_local std::string input_a{}; |
| 351 | thread_local std::string input_b{}; |
| 352 | thread_local std::string func_string{}; |
| 353 | thread_local std::string infix_string{}; |
| 354 | get_operand_string(operands.operands[0], operands.operand_operations[0], ctx, input_a); |
| 355 | get_operand_string(operands.operands[1], operands.operand_operations[1], ctx, input_b); |
| 356 | get_notation(type, func_string, infix_string); |
| 357 | |
| 358 | // These cases aren't strictly necessary and are just here for parity with the old recompiler output. |
| 359 | if (type == BinaryOpType::Less && !((operands.operands[1] == Operand::Zero && operands.operand_operations[1] == UnaryOpType::None) || (operands.operands[0] == Operand::Fs || operands.operands[0] == Operand::FsDouble))) { |
| 360 | expr_string = fmt::format("{} {} {} ? 1 : 0", input_a, infix_string, input_b); |
| 361 | } |
| 362 | else if (type == BinaryOpType::Equal && operands.operands[1] == Operand::Zero && operands.operand_operations[1] == UnaryOpType::None) { |
| 363 | expr_string = "!" + input_a; |
| 364 | } |
| 365 | else if (type == BinaryOpType::NotEqual && operands.operands[1] == Operand::Zero && operands.operand_operations[1] == UnaryOpType::None) { |
| 366 | expr_string = input_a; |
| 367 | } |
| 368 | // End unnecessary cases. |
| 369 | |
| 370 | // TODO encode these ops to avoid needing special handling. |
| 371 | else if (type == BinaryOpType::LWL || type == BinaryOpType::LWR || type == BinaryOpType::LDL || type == BinaryOpType::LDR) { |
| 372 | expr_string = fmt::format("{}(rdram, {}, {}, {})", func_string, output, input_a, input_b); |
| 373 | } |
| 374 | else if (!func_string.empty() && !infix_string.empty()) { |
| 375 | expr_string = fmt::format("{}({} {} {})", func_string, input_a, infix_string, input_b); |
| 376 | } |
| 377 | else if (!func_string.empty()) { |
| 378 | expr_string = fmt::format("{}({}, {})", func_string, input_a, input_b); |
| 379 | } |
| 380 | else if (!infix_string.empty()) { |
| 381 | expr_string = fmt::format("{} {} {}", input_a, infix_string, input_b); |
| 382 | } |
| 383 | else { |
| 384 | // Handle special cases |
| 385 | if (type == BinaryOpType::True) { |
| 386 | expr_string = "1"; |
| 387 | } |
| 388 | else if (type == BinaryOpType::False) { |
| 389 | expr_string = "0"; |
| 390 | } |
| 391 | assert(false && "Binary operation must have either a function or infix!"); |
| 392 | } |
| 393 | } |
| 394 | |
| 395 | void N64Recomp::CGenerator::emit_function_start(const std::string& function_name, size_t func_index) const { |
| 396 | (void)func_index; |
nothing calls this directly
no outgoing calls
no test coverage detected