4 ms·
That doesn't really solve the problem, and has several deficiencies. A split stream might seem complicated, but IMHO it's an amazingly clean way of simplifying
by Veedrac 11y ago
That doesn't really solve the problem, and has several deficiencies. A split stream might seem complicated, but IMHO it's an amazingly clean way of simplifying the problem.
---
The problem is not figuring out what sizes things are, but the routing. When you have 30+ instructions a cycle, you need to route a lot to a lot of different places. You also can't do a parallel read since the size of previous instructions affects the placement of the next instruction - you will eventually fix this with routing but it's not easy.
Consider a 30-wide instruction. Decoding it involves knowing where in the instruction stream it starts. This can only be known once the prior instruction is partially parsed.
Consider its later half - this can only be read after the first half is read. In your case, you actually only need to read the 2-bit prefixes but the difficulty remains.
With a split instruction stream, since there are two independent (at least until a branch) program counters so you have twice the contextual information. You already know where the second half starts from the prior instruction.
One more great thing about this is that the contextual information is preserved in jumps, without increasing the size of jump instructions. Even if prior instructions had metadata about splitting the next instruction for parsing (at yet more space wastage), this would be lost across jumps. That would worsen jump latency, which is a common bottleneck.
The above point is way more important if you expect a flow instruction almost every bundle, due to the massive ILP the Mill has.
---
> With instruction sizes of 1-4 bytes, you could store instruction sizes in 2 bits per instruction.
However, the Mill does not constrain its instruction sizes to multiples of 8 bits. This means either you'd lose that bonus or you'd need even more bits.
The Mill also splits which instructions are allowed in each half. Not only does this give you a free implicit bit, it again halves the amount of work for each decoder. This could probably happen with interleaved halves like you describe, but not without difficulty.
> For example, you could use 0x01 both for INC and ADD IMMEDIATE VALUE, where it means the former if the instruction length is 1, the latter if it is longer, with the size of the immediate determined by the size of the instruction. Would that be a net win?
The answer is no. The instructions codes are generated to be space optimal. I'm not sure how this is done, but it has been stated. They also leave it open for metadata like you mention to be included in each instruction stream, and in fact their blocks do have headers.
> creating those two streams that somehow must work together to do what a single statement sequence in the source code does
Given the instructions are disjoint and they only need synchronization at jumps, I would be very surprised if this was problematic.
- Someone 11y ago"The problem is not figuring out what sizes things are, but the routing" Aha! Thanks. "Given the instructions are disjoint and they only need synchronization at jumps" But they are (AFAIK) executing a single thread of execution, so creating those disjoint streams in general will be far from easy, won't it? if it were possible to do that, we would see a 2x speed up of single-threaded code on CPUs with two cores.
- renox 11y agoUh? That's quite different AFAIK: two CPU cores doesn't share their registers, those disjoint streams do.
- Someone 11y agoI know this architecture tries to innovate everywhere, but disjoint streams that share registers, but not caches? I haven't read all documentation on the Mill, but I would expect that that sharing part means that both streams can read or one can write each register.
- willvarfar 11y ago(Mill team) The Mill is Havard architecture. Each Mill core has two separate physically separated instruction caches that each feed a dedicated decoder, which decodes for a distinct set of pipelines.
- renox 11y ago> which decodes for a distinct set of pipelines I apologize for my mistake, I hope that it hasn't induced too many confusions (I take it that 'distinct set of pipelines' means distinct operation and 'belt' so the registers aren't shared).
- willvarfar 11y agoNo need to apologise :) The pipelines are distinct, but the set of ops that any particular pipeline supports is arbitrary (as in picked by the HW guys who have to fit the FUs in) and the belt is shared. The belt is where the two sides join. We tend to get good entropy putting the flow on one side and exec on the other, and that's nice for humans to model too, but there is no technical requirement. The thing about the Mill is its easily customisable. If you have some new FU (lets say you want a particular op that assists in say encrpytion) you can choose where you put it, and how many pipelines you put it in etc.