using System; using System.Reflection; using Translator.Core.Analysis.Representation; using Translator.Core.CodeGen; using Translator.Core.Ir; using Translator.Core.Representation; using Xunit; namespace Translator.Tests; public class CodeGenExpressionCoverageTests { private static readonly Type GeneratorType = typeof(CxxLinearCodeGenerator); private static T InvokePrivate(string name, params object?[] args) { var method = GeneratorType.GetMethod(name, BindingFlags.NonPublic | BindingFlags.Static); Assert.NotNull(method); return (T)method!.Invoke(null, args)!; } private static string FormatBinary(IrBinary binary, RepresentationEnvironment types) { var left = InvokePrivate("ToExpression", binary.Left, types); var right = InvokePrivate("ToExpression", binary.Right, types); return InvokePrivate("BinaryExpressionWithOperands", binary, left, right); } [Fact] public void BinaryExpression_FormatsRareOperations() { var types = new RepresentationEnvironment(); Assert.Equal( "(static_cast(ctx->gpr[3]))", FormatBinary(new IrBinary("r4", IrValue.Register("r3"), IrValue.Imm(12), "sext"), types)); Assert.Equal( "~(ctx->gpr[3] & ctx->gpr[4])", FormatBinary(new IrBinary("r5", IrValue.Register("r3"), IrValue.Register("r4"), "nand"), types)); Assert.Equal( "~(ctx->gpr[3] ^ ctx->gpr[4])", FormatBinary(new IrBinary("r5", IrValue.Register("r3"), IrValue.Register("r4"), "eqv"), types)); Assert.Equal( "std::sqrt(ctx->fpr[1].d)", FormatBinary(new IrBinary("f2", IrValue.Register("f1"), IrValue.Register("f3"), "fsqrt"), types)); Assert.Equal( "(ctx->fpr[1].d - ctx->fpr[2].d)", FormatBinary(new IrBinary("f3", IrValue.Register("f1"), IrValue.Register("f2"), "fcmp"), types)); Assert.Equal( "PPC_Divw(static_cast(ctx->gpr[7]), static_cast(ctx->gpr[8]))", FormatBinary(new IrBinary("r9", IrValue.Register("r7"), IrValue.Register("r8"), "div"), types)); Assert.Equal( "(static_cast(static_cast(ctx->gpr[9])))", FormatBinary(new IrBinary("r10", IrValue.Register("r9"), IrValue.Imm(0), "sext16"), types)); Assert.Equal( "(CompareUnsigned(static_cast(ctx->gpr[11]), static_cast(ctx->gpr[12])))", FormatBinary(new IrBinary("r13", IrValue.Register("r11"), IrValue.Register("r12"), "sub_u"), types)); Assert.Equal( "PPC_Fctiwz(ctx->fpr[4].d)", FormatBinary(new IrBinary("f5", IrValue.Register("f4"), IrValue.Imm(0), "fctiwz"), types)); Assert.Equal( "PPC_Fctiw(ctx->fpr[4].d)", FormatBinary(new IrBinary("f5", IrValue.Register("f4"), IrValue.Imm(0), "fctiw"), types)); Assert.Equal( "PPC_Slw(static_cast(ctx->gpr[3]), static_cast(ctx->gpr[4]))", FormatBinary(new IrBinary("r5", IrValue.Register("r3"), IrValue.Register("r4"), "ppc_slw"), types)); Assert.Equal( "PPC_Srw(static_cast(ctx->gpr[3]), static_cast(ctx->gpr[4]))", FormatBinary(new IrBinary("r5", IrValue.Register("r3"), IrValue.Register("r4"), "ppc_srw"), types)); Assert.Equal( "PPC_Sraw(static_cast(ctx->gpr[3]), static_cast(ctx->gpr[4]))", FormatBinary(new IrBinary("r5", IrValue.Register("r3"), IrValue.Register("r4"), "ppc_sraw"), types)); } [Fact] public void RegisterHelpers_MapSpecialRegistersAndConditions() { var types = new RepresentationEnvironment(); Assert.Equal("ctx->cr", InvokePrivate("RegisterToCtxRead", "cr", types)); Assert.Equal("((ctx->cr >> 0) & 0xF)", InvokePrivate("RegisterToCtxRead", "cr7", types)); Assert.Equal("ctx->srr0", InvokePrivate("RegisterToCtxRead", "srr0", types)); Assert.Equal("ctx->srr1", InvokePrivate("RegisterToCtxRead", "srr1", types)); Assert.Equal("ctx->hid0", InvokePrivate("RegisterToCtxRead", "hid0", types)); Assert.Equal("ctx->hid1", InvokePrivate("RegisterToCtxRead", "hid1", types)); Assert.Equal("ctx->hid2", InvokePrivate("RegisterToCtxRead", "hid2", types)); Assert.Equal("ctx->gqr[3]", InvokePrivate("RegisterToCtxRead", "gqr3", types)); Assert.Equal("0", InvokePrivate("RegisterToCtxRead", "gqr9", types)); Assert.Equal("ctx->cr", InvokePrivate("RegisterToCtxWrite", "cr", types)); Assert.Equal("cr6", InvokePrivate("RegisterToCtxWrite", "cr6", types)); Assert.Equal("ctx->hid2", InvokePrivate("RegisterToCtxWrite", "hid2", types)); Assert.Equal("ctx->gqr[5]", InvokePrivate("RegisterToCtxWrite", "gqr5", types)); Assert.Equal("gqr8", InvokePrivate("RegisterToCtxWrite", "gqr8", types)); Assert.Equal("0", InvokePrivate("ToExpression", new IrValue("temporary"), types)); Assert.Equal("tmp_local", InvokePrivate("ToExpression", IrValue.Register("tmp_local"), types)); Assert.Equal("(ctx->ctr != 0)", InvokePrivate("ToCondition", "bdnz", "ctr", types)); Assert.Equal("(ctx->ctr == 0)", InvokePrivate("ToCondition", "bdz", "ctr", types)); Assert.Equal("((ctx->cr & 0x00000001u) != 0)", InvokePrivate("ToCondition", "bso", "cr7", types)); Assert.Equal("((ctx->cr & 0x00000001u) == 0)", InvokePrivate("ToCondition", "bns", "cr7", types)); Assert.Equal("flag_local", InvokePrivate("ToCondition", "custom", "flag_local", types)); Assert.Equal("ctx->gpr[4]", InvokePrivate("Address", new IrAddress("r4", 0), types)); Assert.Equal("(ctx->gpr[4] + 16)", InvokePrivate("Address", new IrAddress("r4", 16), types)); Assert.Equal("r3", InvokePrivate("BaseRegister", "r3_17")); Assert.Equal("tmp", InvokePrivate("BaseRegister", "tmp_local")); Assert.Equal(8, InvokePrivate("Bits", 1)); Assert.Equal(16, InvokePrivate("Bits", 2)); Assert.Equal(64, InvokePrivate("Bits", 8)); Assert.Equal(32, InvokePrivate("Bits", 4)); } }