Cosmos icon indicating copy to clipboard operation
Cosmos copied to clipboard

Either 'bitshift' or 'bitwise or' operators cause the kernel to lock up

Open terminal-cs opened this issue 1 year ago • 8 comments

Area of Cosmos - What area of Cosmos are we dealing with?

Unknown, could be il2cpu

Expected Behaviour - What do you think that should happen?

The operations should complete successfully - Tested working outside of cosmos

Actual Behaviour - What unexpectedly happens?

The entire kernel locks up and nothing can be done

Reproduction - How did you get this error to appear?

byte A = 255;
byte R = 255;
byte G = 255;
byte B = 255; 

uint Result = (uint)(A << 24 | R << 16 | G << 8 | B);

Console.WriteLine(Result);

Version - Were you using the User Kit or Dev Kit? And what User Kit version or Dev Kit commit (Cosmos, IL2CPU, X#)?

Latest

terminal-cs avatar May 13 '23 06:05 terminal-cs

mmm so i was not going insane

    public static bool HasFlag(ref Int32 data, int flagOffset)
    {
        if (flagOffset is < 0 or > 31) throw new ArgumentOutOfRangeException("flagOffset");
        var flag = data >> flagOffset;
        return (flag & 1) == 1;
    }

i think it might be this that that is locking up my CPUID code

zarlo avatar May 13 '23 07:05 zarlo

That's interesting... Cosmos uses bit-shifts all over the code base internally. Can you post a snippet of the Assembly code it generated that corresponds to the shr IL op-code? You can try using QEMU to see at which address it hangs and locate the appropriate IL op-code label with the map file.

As a work-around, you can try using unchecked((uint)(A * 16777216u + R * 65536u + G * 256u + B));. This is equivalent to the bit-shifts and bitwise operations (but would perform worse on x86).

ascpixi avatar May 13 '23 10:05 ascpixi

idk but something's a bit odd there

public override void Execute(Il2cpuMethodInfo aMethod, ILOpCode aOpCode )
        {
			var xStackItem_ShiftAmount = aOpCode.StackPopTypes[0];
			var xStackItem_Value = aOpCode.StackPopTypes[1];
            var xStackItem_Value_Size = SizeOfType(xStackItem_Value);

            XS.Pop(XSRegisters.ECX); // shift amount
#if DOTNETCOMPATIBLE
			if (xStackItem_Value.Size == 4)
#else
            if (xStackItem_Value_Size <= 4)
#endif
			{
                // To retain the sign bit we must use ShiftRightArithmetic and not ShiftRight!
                //XS.ShiftRight(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true, size: RegisterSize.Int32);
                XS.ShiftRightArithmetic(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true, size: RegisterSize.Int32);
            }
#if DOTNETCOMPATIBLE
			else if (xStackItem_Value_Size == 8)
#else
			else if (xStackItem_Value_Size <= 8)
#endif
			{
				string BaseLabel = GetLabel(aMethod, aOpCode) + ".";
				string HighPartIsZero = BaseLabel + "HighPartIsZero";
				string End_Shr = BaseLabel + "End_Shr";

				// [ESP] is low part
				// [ESP + 4] is high part

				// move high part in EAX
				XS.Set(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 4);

				XS.Compare(XSRegisters.CL, 32, size: RegisterSize.Byte8);
				XS.Jump(CPU.ConditionalTestEnum.AboveOrEqual, HighPartIsZero);

				// shift lower part
                XS.ShiftRightDouble(ESP, EAX, CL, destinationIsIndirect: true);
                // shift higher part
                // To retain the sign bit we must use ShiftRightArithmetic and not ShiftRight!
                //XS.ShiftRight(ESP, CL, destinationDisplacement: 4, size: RegisterSize.Int32);
                XS.ShiftRightArithmetic(ESP, CL, destinationDisplacement: 4, size: RegisterSize.Int32);
                XS.Jump(End_Shr);

				XS.Label(HighPartIsZero);

				// remove bits >= 32, so that CL max value could be only 31
				XS.And(XSRegisters.CL, 0x1f, size: RegisterSize.Byte8);

                // shift high part and move it in low part
                // To retain the sign bit we must use ShiftRightArithmetic and not ShiftRight!
                XS.ShiftRightArithmetic(XSRegisters.EAX, XSRegisters.CL);
                XS.Set(ESP, EAX, destinationIsIndirect: true);
                // replace unknown high part with a zero
                XS.Set(ESP, 0, destinationIsIndirect: true, destinationDisplacement: 4);
				//new CPUx86.Mov { DestinationReg = CPUx86.RegistersEnum.ESP, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceValue = 0};

				XS.Label(End_Shr);
			}
			else
				throw new NotSupportedException("A size bigger 8 not supported at Shr!");
            /*string xLabelName = AppAssembler.TmpPosLabel(aMethod, aOpCode);
            var xStackItem_ShiftAmount = Assembler.Stack.Pop();
            var xStackItem_Value = Assembler.Stack.Peek();
            if( xStackItem_Value.Size <= 4 )
            {
                XS.Pop(XSRegisters.ECX); // shift amount
                XS.ShiftRight(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true);
            }
            else if( xStackItem_Value.Size <= 8 )
            {
				XS.Pop(XSRegisters.ECX); // shift amount
				// [ESP] is high part
				// [ESP + 4] is low part
				XS.Mov(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 4);
				// shift low part
				new CPUx86.ShiftRightDouble { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.EAX, ArgumentReg = CPUx86.Registers.CL };
				// shift high part
				XS.ShiftRight(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true, size: RegisterSize.Int32);
            }*/
            }
        }

AsertCreator avatar May 13 '23 11:05 AsertCreator

unchecked((uint)(A * 16777216u + R * 65536u + G * 256u + B));

That code works for now, thanks.

I'm already working with quajak on this

terminal-cs avatar May 13 '23 20:05 terminal-cs

idk but something's a bit odd there

public override void Execute(Il2cpuMethodInfo aMethod, ILOpCode aOpCode )
        {
			var xStackItem_ShiftAmount = aOpCode.StackPopTypes[0];
			var xStackItem_Value = aOpCode.StackPopTypes[1];
            var xStackItem_Value_Size = SizeOfType(xStackItem_Value);

            XS.Pop(XSRegisters.ECX); // shift amount
#if DOTNETCOMPATIBLE
			if (xStackItem_Value.Size == 4)
#else
            if (xStackItem_Value_Size <= 4)
#endif
			{
                // To retain the sign bit we must use ShiftRightArithmetic and not ShiftRight!
                //XS.ShiftRight(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true, size: RegisterSize.Int32);
                XS.ShiftRightArithmetic(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true, size: RegisterSize.Int32);
            }
#if DOTNETCOMPATIBLE
			else if (xStackItem_Value_Size == 8)
#else
			else if (xStackItem_Value_Size <= 8)
#endif
			{
				string BaseLabel = GetLabel(aMethod, aOpCode) + ".";
				string HighPartIsZero = BaseLabel + "HighPartIsZero";
				string End_Shr = BaseLabel + "End_Shr";

				// [ESP] is low part
				// [ESP + 4] is high part

				// move high part in EAX
				XS.Set(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 4);

				XS.Compare(XSRegisters.CL, 32, size: RegisterSize.Byte8);
				XS.Jump(CPU.ConditionalTestEnum.AboveOrEqual, HighPartIsZero);

				// shift lower part
                XS.ShiftRightDouble(ESP, EAX, CL, destinationIsIndirect: true);
                // shift higher part
                // To retain the sign bit we must use ShiftRightArithmetic and not ShiftRight!
                //XS.ShiftRight(ESP, CL, destinationDisplacement: 4, size: RegisterSize.Int32);
                XS.ShiftRightArithmetic(ESP, CL, destinationDisplacement: 4, size: RegisterSize.Int32);
                XS.Jump(End_Shr);

				XS.Label(HighPartIsZero);

				// remove bits >= 32, so that CL max value could be only 31
				XS.And(XSRegisters.CL, 0x1f, size: RegisterSize.Byte8);

                // shift high part and move it in low part
                // To retain the sign bit we must use ShiftRightArithmetic and not ShiftRight!
                XS.ShiftRightArithmetic(XSRegisters.EAX, XSRegisters.CL);
                XS.Set(ESP, EAX, destinationIsIndirect: true);
                // replace unknown high part with a zero
                XS.Set(ESP, 0, destinationIsIndirect: true, destinationDisplacement: 4);
				//new CPUx86.Mov { DestinationReg = CPUx86.RegistersEnum.ESP, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceValue = 0};

				XS.Label(End_Shr);
			}
			else
				throw new NotSupportedException("A size bigger 8 not supported at Shr!");
            /*string xLabelName = AppAssembler.TmpPosLabel(aMethod, aOpCode);
            var xStackItem_ShiftAmount = Assembler.Stack.Pop();
            var xStackItem_Value = Assembler.Stack.Peek();
            if( xStackItem_Value.Size <= 4 )
            {
                XS.Pop(XSRegisters.ECX); // shift amount
                XS.ShiftRight(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true);
            }
            else if( xStackItem_Value.Size <= 8 )
            {
				XS.Pop(XSRegisters.ECX); // shift amount
				// [ESP] is high part
				// [ESP + 4] is low part
				XS.Mov(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 4);
				// shift low part
				new CPUx86.ShiftRightDouble { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.EAX, ArgumentReg = CPUx86.Registers.CL };
				// shift high part
				XS.ShiftRight(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true, size: RegisterSize.Int32);
            }*/
            }
        }

Where is this code located?

terminal-cs avatar May 14 '23 15:05 terminal-cs

here

AsertCreator avatar May 14 '23 23:05 AsertCreator

here

It shows that it hasn't been changed in over a year, it should be fine

terminal-cs avatar May 15 '23 01:05 terminal-cs

at is was this line public override void Execute(Il2cpuMethodInfo aMethod, ILOpCode aOpCode ) before then it was like 6 years

zarlo avatar May 15 '23 01:05 zarlo