CPUID patch

Developer
Jan 27, 2009 at 3:33 AM
The compiler doesn't have CPUID support, which surprised Mike when I mentioned it to him a few weeks back. Here's a patch that adds support for it. I might've gone overboard on the various files to edit. I was just basically adding the new code blocks wherever I saw the hlt instruction was previously added. :)

http://sbalmos.fastmail.fm/cpuid.patch

(Has anyone mentioned lately how much we love CodePlex? :D)

--S
Coordinator
Jan 27, 2009 at 4:34 AM

The patch is incomplete and results in the following error messages:

Error 1 'Mosa.Platforms.x86.IRToX86TransformationStage' does not implement interface member 'Mosa.Platforms.x86.IX86InstructionVisitor<Mosa.Runtime.CompilerFramework.CodeTransformationStage.Context>.CpuId(Mosa.Platforms.x86.Instructions.Intrinsics.CpuIdInstruction, Mosa.Runtime.CompilerFramework.CodeTransformationStage.Context)' X:\MosaTF\trunk\Mosa\Platforms\x86\IRToX86TransformationStage.cs 30 25 Mosa.Platforms.x86

Error 2 'Mosa.Platforms.x86.LongOperandTransformationStage' does not implement interface member 'Mosa.Platforms.x86.IX86InstructionVisitor<Mosa.Runtime.CompilerFramework.CodeTransformationStage.Context>.CpuId(Mosa.Platforms.x86.Instructions.Intrinsics.CpuIdInstruction, Mosa.Runtime.CompilerFramework.CodeTransformationStage.Context)' X:\MosaTF\trunk\Mosa\Platforms\x86\LongOperandTransformationStage.cs 33 25 Mosa.Platforms.x86

Coordinator
Jan 27, 2009 at 6:09 AM
Thanks! I remember having a discussion with rootnode (however this may be a delusion of the feverish state I'm in right now; got the tonsillitis from my kid) about the representation of the CPUID parameter sets (e.g. long or int) etc. I can't take a look at it right now, but could you post some more details?
Developer
Jan 27, 2009 at 5:44 PM
Recommitted. Those two files weren't selected in the commit / patch list, for some reason.

tgiphil wrote:

From: tgiphil

The patch is incomplete and results in the following error messages:

Error 1 'Mosa.Platforms.x86.IRToX86TransformationStage' does not implement interface member 'Mosa.Platforms.x86.IX86InstructionVisitor<Mosa.Runtime.CompilerFramework.CodeTransformationStage.Context>.CpuId(Mosa.Platforms.x86.Instructions.Intrinsics.CpuIdInstruction, Mosa.Runtime.CompilerFramework.CodeTransformationStage.Context)' X:\MosaTF\trunk\Mosa\Platforms\x86\IRToX86TransformationStage.cs 30 25 Mosa.Platforms.x86

Error 2 'Mosa.Platforms.x86.LongOperandTransformationStage' does not implement interface member 'Mosa.Platforms.x86.IX86InstructionVisitor<Mosa.Runtime.CompilerFramework.CodeTransformationStage.Context>.CpuId(Mosa.Platforms.x86.Instructions.Intrinsics.CpuIdInstruction, Mosa.Runtime.CompilerFramework.CodeTransformationStage.Context)' X:\MosaTF\trunk\Mosa\Platforms\x86\LongOperandTransformationStage.cs 33 25 Mosa.Platforms.x86


Developer
Jan 28, 2009 at 3:01 AM
There's always Wikipedia. ;) http://en.wikipedia.org/wiki/CPUID. Honestly, looking at that, I think we'd only be interested in parameters 0, 1, and 80000001h. Those are the ones dealing with returning feature sets, vendor strings, etc. Everything else is kind of pointless.

I may have to talk with you or others in IRC about this. But how is one supposed to get the data back out of the registers? We don't have MOV from register to memory, much less MOV from memory to register, in order to set the CPUID parameter. I'm betting this will be some type of composite machine IR stuff. But that's over my head now.

--S

__grover wrote:

From: __grover

Thanks! I remember having a discussion with rootnode (however this may be a delusion of the feverish state I'm in right now; got the tonsillitis from my kid) about the representation of the CPUID parameter sets (e.g. long or int) etc. I can't take a look at it right now, but could you post some more details?

Coordinator
Jan 28, 2009 at 6:17 AM
Ok, now I remember what our talks were about. The issue is: You have no control over the registers allocated or used right now. We only need this in a very small set of places, CPUID being one of them. The original idea of using IRegisterConstraint for this purpose works in theory, but has shown some downsides when I started writing the register allocators. I'm still chewing on a better solution for this. We will pick the right registers for an instruction.

Anyways, if you're getting data back from an instruction like you are in this case, use the ref/out modifiers on the appropriate parameters. Additionally you'll want to provide multiple overloads of CpuId only taking an appropriate number of them - and don't hardcode the function code, as I think there's a couple more interesting to us.
Developer
Feb 3, 2009 at 1:14 AM
Almost done with the rewrite. Though I need help in the new
MachineCodeEmitter block. See current code below:

void ICodeEmitter.CpuId(Operand dst, Operand function)
{
MemoryOperand mopdst = dst as MemoryOperand;

Mov(new RegisterOperand(function.Type, GeneralPurposeRegister.EAX),
function);
Emit(new byte[] { 0x0F, 0xA2 }, null, null, null);
Mov(mopdst, new RegisterOperand(mopdst.Type,
GeneralPurposeRegister.EAX));
Mov(new MemoryOperand(mopdst.Type, mopdst.Base, new
IntPtr(mopdst.Offset.ToInt64() + 4)), new RegisterOperand(dst.Type,
GeneralPurposeRegister.EBX));
Mov(new MemoryOperand(mopdst.Type, mopdst.Base, new
IntPtr(mopdst.Offset.ToInt64() + 8)), new RegisterOperand(dst.Type,
GeneralPurposeRegister.ECX));
Mov(new MemoryOperand(mopdst.Type, mopdst.Base, new
IntPtr(mopdst.Offset.ToInt64() + 12)), new RegisterOperand(dst.Type,
GeneralPurposeRegister.EDX));
}

This fails because Mov() is apparently private(???). Further, I'm not so
sure on the offset calculation construction. Comments and corrections
are grateful. Gracias.

--S

__grover wrote:
>
> From: __grover
>
> Ok, now I remember what our talks were about. The issue is: You have
> no control over the registers allocated or used right now. We only
> need this in a very small set of places, CPUID being one of them. The
> original idea of using IRegisterConstraint for this purpose works in
> theory, but has shown some downsides when I started writing the
> register allocators. I'm still chewing on a better solution for this.
> We will pick the right registers for an instruction.
>
> Anyways, if you're getting data back from an instruction like you are
> in this case, use the ref/out modifiers on the appropriate parameters.
> Additionally you'll want to provide multiple overloads of CpuId only
> taking an appropriate number of them - and don't hardcode the function
> code, as I think there's a couple more interesting to us.
>
> Read the full discussion online
> <http://www.codeplex.com/mosa/Thread/View.aspx?ThreadId=45341&ANCHOR#Post151614>.
>
> To add a post to this discussion, reply to this email
> ([email removed]
> <mailto:[email removed]?subject=%5Bmosa:45341%5D>)
>
> To start a new discussion for this project, email
> [email removed] <mailto:[email removed]>
>
> You are receiving this email because you subscribed to this discussion
> on CodePlex. You can unsubscribe or change your settings
> <http://www.codeplex.com/site/discussions/project/unsubscribe/mosa> on
> codePlex.com.
>
> Please note: Images and attachments will be removed from emails. Any
> posts to this discussion will also be available online at codeplex.com
>
Coordinator
Feb 3, 2009 at 8:29 AM
Edited Feb 3, 2009 at 8:42 AM
void ICodeEmitter.CpuId(Operand dst, Operand function)
{
    MemoryOperand mopdst = dst as MemoryOperand;
    Emit(new RegisterOperand(function.Type, GeneralPurposeRegister.EAX),  function, cd_mov);
    Emit(new byte[] { 0x0F, 0xA2 }, null, null, null);
    Emit(mopdst, new RegisterOperand(mopdst.Type, GeneralPurposeRegister.EAX), cd_mov);
    Emit(new MemoryOperand(mopdst.Type, mopdst.Base, new IntPtr(mopdst.Offset.ToInt64() + 4)), new RegisterOperand(dst.Type, GeneralPurposeRegister.EBX), cd_mov);
    Emit(new MemoryOperand(mopdst.Type, mopdst.Base, new IntPtr(mopdst.Offset.ToInt64() + 8)), new RegisterOperand(dst.Type, GeneralPurposeRegister.ECX), cd_mov);
    Emit(new MemoryOperand(mopdst.Type, mopdst.Base, new IntPtr(mopdst.Offset.ToInt64() + 12)), new RegisterOperand(dst.Type, GeneralPurposeRegister.EDX), cd_mov);
}

Just use the Emit function to create the MOVs.

But this is not an elegant way to solve it if you ask me. There has to be some other way. But for the time being, this should do it.
Developer
Feb 3, 2009 at 4:43 PM
Definitely not elegant, especially if there are code changes to Mov() down the road. That's why I was hoping to make calls to Mov() rather than directly emitting mov's myself. But alas... It Seems To Work [tm]. Thanks.

--S

Kintaro wrote:

From: Kintaro

void ICodeEmitter.CpuId(Operand dst, Operand function)
{
MemoryOperand mopdst = dst as MemoryOperand;
Emit(new RegisterOperand(function.Type, GeneralPurposeRegister.EAX),  function, cd_mov);
Emit(new byte[] { 0x0F, 0xA2 }, null, null, null);
Emit(mopdst, new RegisterOperand(mopdst.Type, GeneralPurposeRegister.EAX), cd_mov);
Emit(new MemoryOperand(mopdst.Type, mopdst.Base, new IntPtr(mopdst.Offset.ToInt64() + 4)), new RegisterOperand(dst.Type, GeneralPurposeRegister.EBX), cd_mov);
Emit(new MemoryOperand(mopdst.Type, mopdst.Base, new IntPtr(mopdst.Offset.ToInt64() + 8)), new RegisterOperand(dst.Type, GeneralPurposeRegister.ECX), cd_mov);
Emit(new MemoryOperand(mopdst.Type, mopdst.Base, new IntPtr(mopdst.Offset.ToInt64() + 12)), new RegisterOperand(dst.Type, GeneralPurposeRegister.EDX), cd_mov);
}

Just use the Emit function to crate the MOVs.

But this is not an elegant way to solve it if you ask me. There has to be ome other way. But for the time being, this should do it.

Coordinator
Feb 3, 2009 at 5:15 PM
Guys, ICodeEmitter and its methods are not private. You are unable to call them, because of the explicit interface implementations. Just make them regular methods - e.g. public void Mov(...) - and you can call Mov() to do its job. If for some reason someone is against this, you can still cast this to get to the interface to call Mov() ;)
Coordinator
Feb 3, 2009 at 7:49 PM
I'd recommend to create a CpuID instruction in the native namespace or intrinsics. 

I have a new idea for the register allocator problem. It's just a basic idea at the moment, but after my exam on saturday I'll extend the idea. If it happens to be "stable", it could solve the problems with CPUID too.
Developer
Feb 3, 2009 at 8:58 PM
A method in Native.cs, and a matching intrinsic, already exists for cpuid.

Kintaro wrote:

From: Kintaro

I'd recommend to create a CpuID instruction in the native namespace or intrinsics. 

I have a new idea for the register allocator problem. It's just a basic idea at the moment, but after my exam on saturday I'll extend the idea. If it happens to be "stable", it could solve the problems with CPUID too.

Coordinator
Feb 3, 2009 at 9:25 PM
Ouch, my bad.