Remove unnecessary register state stores for calls when the callee is know

This commit is contained in:
gdkchan 2019-02-25 13:03:53 -03:00
commit 07eb4a329d
6 changed files with 65 additions and 13 deletions

View file

@ -22,6 +22,8 @@ namespace ChocolArm64.Instructions
if (!context.TryOptEmitSubroutineCall()) if (!context.TryOptEmitSubroutineCall())
{ {
context.EmitStoreState();
context.TranslateAhead(imm); context.TranslateAhead(imm);
context.EmitLdarg(TranslatedSub.StateArgIdx); context.EmitLdarg(TranslatedSub.StateArgIdx);

View file

@ -315,17 +315,19 @@ namespace ChocolArm64.Translation
return false; return false;
} }
if (!_cache.TryGetSubroutine(((OpCodeBImmAl64)CurrOp).Imm, out TranslatedSub subroutine)) if (!_cache.TryGetSubroutine(((OpCodeBImmAl64)CurrOp).Imm, out TranslatedSub sub))
{ {
return false; return false;
} }
EmitStoreState(sub);
for (int index = 0; index < TranslatedSub.FixedArgTypes.Length; index++) for (int index = 0; index < TranslatedSub.FixedArgTypes.Length; index++)
{ {
EmitLdarg(index); EmitLdarg(index);
} }
EmitCall(subroutine.Method); EmitCall(sub.Method);
return true; return true;
} }
@ -603,6 +605,11 @@ namespace ChocolArm64.Translation
_ilBlock.Add(new ILOpCodeStoreState(_ilBlock)); _ilBlock.Add(new ILOpCodeStoreState(_ilBlock));
} }
private void EmitStoreState(TranslatedSub callSub)
{
_ilBlock.Add(new ILOpCodeStoreState(_ilBlock, callSub));
}
public void EmitLdtmp() => EmitLdint(IntGpTmp1Index); public void EmitLdtmp() => EmitLdint(IntGpTmp1Index);
public void EmitSttmp() => EmitStint(IntGpTmp1Index); public void EmitSttmp() => EmitStint(IntGpTmp1Index);

View file

@ -47,7 +47,10 @@ namespace ChocolArm64.Translation
DynamicMethod method = new DynamicMethod(_subName, typeof(long), TranslatedSub.FixedArgTypes); DynamicMethod method = new DynamicMethod(_subName, typeof(long), TranslatedSub.FixedArgTypes);
TranslatedSub subroutine = new TranslatedSub(method, tier); long intNiRegsMask = RegUsage.GetIntNotInputs(_ilBlocks[0]);
long vecNiRegsMask = RegUsage.GetVecNotInputs(_ilBlocks[0]);
TranslatedSub subroutine = new TranslatedSub(method, tier, intNiRegsMask, vecNiRegsMask);
_locals = new Dictionary<Register, int>(); _locals = new Dictionary<Register, int>();

View file

@ -7,9 +7,12 @@ namespace ChocolArm64.Translation
{ {
private ILBlock _block; private ILBlock _block;
public ILOpCodeStoreState(ILBlock block) private TranslatedSub _callSub;
public ILOpCodeStoreState(ILBlock block, TranslatedSub callSub = null)
{ {
_block = block; _block = block;
_callSub = callSub;
} }
public void Emit(ILMethodBuilder context) public void Emit(ILMethodBuilder context)
@ -23,6 +26,15 @@ namespace ChocolArm64.Translation
vecOutputs = RegisterUsage.ClearCallerSavedVecRegs(vecOutputs, context.IsAarch64); vecOutputs = RegisterUsage.ClearCallerSavedVecRegs(vecOutputs, context.IsAarch64);
} }
if (_callSub != null)
{
//Those register are assigned on the callee function, without
//reading it's value first. We don't need to write them because
//they are not going to be read on the callee.
intOutputs &= ~_callSub.IntNiRegsMask;
vecOutputs &= ~_callSub.VecNiRegsMask;
}
StoreLocals(context, intOutputs, RegisterType.Int); StoreLocals(context, intOutputs, RegisterType.Int);
StoreLocals(context, vecOutputs, RegisterType.Vector); StoreLocals(context, vecOutputs, RegisterType.Vector);
} }

View file

@ -238,6 +238,25 @@ namespace ChocolArm64.Translation
return inputs; return inputs;
} }
public long GetIntNotInputs(ILBlock entry) => GetNotInputsImpl(entry, _intPaths.Values);
public long GetVecNotInputs(ILBlock entry) => GetNotInputsImpl(entry, _vecPaths.Values);
private long GetNotInputsImpl(ILBlock entry, IEnumerable<PathIo> values)
{
//Returns a mask with registers that are written to
//before being read. Only those registers that are
//written in all paths, and is not read before being
//written to on those paths, should be set on the mask.
long mask = -1L;
foreach (PathIo path in values)
{
mask &= path.GetOutputs() & ~path.GetInputs(entry);
}
return mask;
}
public long GetIntOutputs(ILBlock block) => _intPaths[block].GetOutputs(); public long GetIntOutputs(ILBlock block) => _intPaths[block].GetOutputs();
public long GetVecOutputs(ILBlock block) => _vecPaths[block].GetOutputs(); public long GetVecOutputs(ILBlock block) => _vecPaths[block].GetOutputs();

View file

@ -12,19 +12,28 @@ namespace ChocolArm64.Translation
{ {
public ArmSubroutine Delegate { get; private set; } public ArmSubroutine Delegate { get; private set; }
public static int StateArgIdx { get; private set; } public static int StateArgIdx { get; }
public static int MemoryArgIdx { get; private set; } public static int MemoryArgIdx { get; }
public static Type[] FixedArgTypes { get; private set; } public static Type[] FixedArgTypes { get; }
public DynamicMethod Method { get; private set; } public DynamicMethod Method { get; }
public TranslationTier Tier { get; private set; } public TranslationTier Tier { get; }
public TranslatedSub(DynamicMethod method, TranslationTier tier) public long IntNiRegsMask { get; }
public long VecNiRegsMask { get; }
public TranslatedSub(
DynamicMethod method,
TranslationTier tier,
long intNiRegsMask,
long vecNiRegsMask)
{ {
Method = method ?? throw new ArgumentNullException(nameof(method));; Method = method ?? throw new ArgumentNullException(nameof(method));;
Tier = tier; Tier = tier;
IntNiRegsMask = intNiRegsMask;
VecNiRegsMask = vecNiRegsMask;
} }
static TranslatedSub() static TranslatedSub()