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
parent 930ff8ff01
commit 07eb4a329d
6 changed files with 65 additions and 13 deletions

View file

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

View file

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

View file

@ -47,7 +47,10 @@ namespace ChocolArm64.Translation
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>();

View file

@ -7,9 +7,12 @@ namespace ChocolArm64.Translation
{
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)
@ -23,6 +26,15 @@ namespace ChocolArm64.Translation
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, vecOutputs, RegisterType.Vector);
}

View file

@ -238,6 +238,25 @@ namespace ChocolArm64.Translation
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 GetVecOutputs(ILBlock block) => _vecPaths[block].GetOutputs();

View file

@ -12,19 +12,28 @@ namespace ChocolArm64.Translation
{
public ArmSubroutine Delegate { get; private set; }
public static int StateArgIdx { get; private set; }
public static int MemoryArgIdx { get; private set; }
public static int StateArgIdx { get; }
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));;
Tier = tier;
Method = method ?? throw new ArgumentNullException(nameof(method));;
Tier = tier;
IntNiRegsMask = intNiRegsMask;
VecNiRegsMask = vecNiRegsMask;
}
static TranslatedSub()