Remove unnecessary register state stores for calls when the callee is know
This commit is contained in:
parent
930ff8ff01
commit
07eb4a329d
6 changed files with 65 additions and 13 deletions
|
@ -22,6 +22,8 @@ namespace ChocolArm64.Instructions
|
|||
|
||||
if (!context.TryOptEmitSubroutineCall())
|
||||
{
|
||||
context.EmitStoreState();
|
||||
|
||||
context.TranslateAhead(imm);
|
||||
|
||||
context.EmitLdarg(TranslatedSub.StateArgIdx);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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>();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Add table
Reference in a new issue