// Data structure used for computing desired registers.
var desired desiredState
+ desiredSecondReg := map[ID][4]register{} // desired register allocation for 2nd part of a tuple
// Desired registers for inputs & outputs for each instruction in the block.
type dentry struct {
s.curBlock = b
s.startRegsMask = 0
s.usedSinceBlockStart = 0
+ clear(desiredSecondReg)
// Initialize regValLiveSet and uses fields for this block.
// Walk backwards through the block doing liveness analysis.
}
dinfo[i].in[j] = desired.get(a.ID)
}
+ if v.Op == OpSelect1 && prefs[0] != noRegister {
+ // Save desired registers of select1 for
+ // use by the tuple generating instruction.
+ desiredSecondReg[v.Args[0].ID] = prefs
+ }
}
// Process all the non-phi values.
}
}
}
+ if out.idx == 1 {
+ if prefs, ok := desiredSecondReg[v.ID]; ok {
+ for _, r := range prefs {
+ if r != noRegister && (mask&^s.used)>>r&1 != 0 {
+ // Desired register is allowed and unused.
+ mask = regMask(1) << r
+ break
+ }
+ }
+ }
+ }
// Avoid registers we're saving for other values.
if mask&^desired.avoid&^s.nospill&^s.used != 0 {
mask &^= desired.avoid
// Registers it would like to be in, in priority order.
// Unused slots are filled with noRegister.
// For opcodes that return tuples, we track desired registers only
- // for the first element of the tuple.
+ // for the first element of the tuple (see desiredSecondReg for
+ // tracking the desired register for second part of a tuple).
regs [4]register
}
return a[0] + a[1]
}
+func dwloadResult1(p *string) string {
+ // arm64:"LDP\t\\(R0\\), \\(R0, R1\\)"
+ return *p
+}
+
+func dwloadResult2(p *[2]int64) (int64, int64) {
+ // arm64:"LDP\t\\(R0\\), \\(R1, R0\\)"
+ return p[1], p[0]
+}
+
// ---------------------------------- //
// Arm64 double-register stores //
// ---------------------------------- //