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())
|
if (!context.TryOptEmitSubroutineCall())
|
||||||
{
|
{
|
||||||
|
context.EmitStoreState();
|
||||||
|
|
||||||
context.TranslateAhead(imm);
|
context.TranslateAhead(imm);
|
||||||
|
|
||||||
context.EmitLdarg(TranslatedSub.StateArgIdx);
|
context.EmitLdarg(TranslatedSub.StateArgIdx);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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>();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue