Skip to main content

rucc_codegen/
wide.rs

1//! The integer that is wider than a register, as the two registers it is held in.
2//!
3//! `__int128` is the one integer a C program on this machine writes that no register holds.
4//! Everything else the front end produces is a width the machine has, or is a width
5//! [`crate::widths`] rounds up into one, and neither of those is true here: there is nothing to
6//! round up into above sixty four bits. What there is, is two registers, and the convention already
7//! says so. System V classifies a `__int128` as two eightbytes of class INTEGER, so it travels in a
8//! pair of general purpose registers, comes back in the pair a return comes back in, and sits in
9//! memory as two words with the low one first. That is what this pass writes down.
10//!
11//! Every value a hundred and twenty eight bits wide becomes two values of sixty four, a low half
12//! and a high half, and every instruction over such a value becomes instructions over the halves.
13//! After it there is no value of that width left anywhere in the function, which is what lets the
14//! rest of the back end stay written about widths the machine has. Nothing below this knows the
15//! type existed.
16//!
17//! # Why a pass and not a rule
18//!
19//! A rule matches a term and rewrites it into instructions of the machine, and the selector works a
20//! value at a time. There is no register a value this wide can be selected into, so there is
21//! nothing for a rule to produce, and a rule that produced a pair would have to say which register
22//! each half landed in, which is the allocator's answer and not a rule's. So the splitting happens
23//! before selection, in the IR, where a value is still something a pass may make two of. That is
24//! the same reasoning [`crate::widths`] follows from the other end, and the two are the two halves
25//! of one sentence: nothing reaching the selector is at a width the machine has no register for.
26//!
27//! # What crosses the boundary
28//!
29//! A parameter and a return value are agreed with something this compilation is not looking at, so
30//! splitting one is a claim about where the two halves are. The claim is true when both halves land
31//! in registers, because the convention hands out argument registers in order and two halves in a
32//! row take the two registers the whole value would have taken. It is not true when they do not: a
33//! value the convention could not fit in registers travels in the argument area as sixteen bytes
34//! aligned to sixteen, and two independent words travel as two words each aligned to eight, which
35//! is a different place as soon as an odd number of words went before them. So a function whose
36//! wide parameter would run out of registers is left exactly as it was and refused by name, the
37//! same as a function this pass does not understand. `tamnd/rucc#351` carries what passing one in
38//! memory would take, which is a form of parameter the IR has no way to spell today.
39//!
40//! # Dividing and converting are calls into the runtime
41//!
42//! Every other operation at this width is the same operation over the halves with whatever crossed
43//! between them put back. A quotient is not. The halves of a quotient are not a function of the
44//! halves of its operands taken apart, at this width or at any other, which is why every compiler's
45//! runtime has a division routine in it and none of them has an addition one. So a divide and a
46//! remainder become a call to the routines `runtime/builtins/div.c` defines, which are libgcc's four
47//! names and libgcc's signatures, and `spec/12-abi-and-runtime.md` section 12.8 is what they are.
48//!
49//! A conversion to or from a floating point value is the other one, for a plainer reason: the
50//! machine's own conversion reaches sixty four bits and no further, so there is no instruction to
51//! split into. Those are the eight names `runtime/builtins/convert.c` defines, one for each of a
52//! signed and an unsigned integer against a `float` and a `double` in each direction, and the four
53//! `runtime/builtins/quad.c` defines for a `_Float128`, which has no instruction of its own at any
54//! width and so is a call here for both reasons at once. An eighty bit float is not among them,
55//! because this machine has no register that holds one and the back end says so, which is
56//! tamnd/rucc#326, so a function converting at that width is left alone here and refused below the
57//! way every function of this width used to be.
58//!
59//! The call is asked for with the halves already in it, four parameters of sixty four bits for the
60//! two operands of a divide and two results for the answer, or two parameters and a float, or a
61//! float and two results, which is the shape this pass gives a call it found in the program anyway.
62//! Both ends agree because the convention puts a `__int128` argument in two registers in a row and
63//! hands out argument registers in order, which is the same sentence the section below about
64//! crossing the boundary is.
65//!
66//! That is the shape on every convention that has registers for a value this wide and it is not the
67//! shape on Windows x64, where such a value travels as the address of a copy the caller made and an
68//! integer this wide comes back whole in a vector register. The one place the two are told apart is
69//! where the call is built, by asking the ABI the same question a call in the program is asked, so
70//! everything above it goes on describing the call in halves and nothing above it names a target.
71
72use std::collections::{HashMap, HashSet};
73
74use rucc_base::Interner;
75use rucc_ir::{
76    Abi, Block, BlockCall, CallInfo, Def, Extra, Flags, Float, Func, Imm, Inst, InstData, IntPred,
77    MemInfo, MemOrder, Opcode, Param, Restrict, Signature, Type, Value,
78};
79use rucc_target::{AbiDescription, CallRegs, Places, Where};
80
81use crate::capability;
82use crate::expand;
83
84/// The width this pass is about, which is the one width a C program writes that no register holds.
85const WIDE: u32 = 128;
86
87/// What the capability table calls that width, which is how the rule language spells one.
88const MODE: &str = "i128";
89
90/// The width each half is, which is a register on every target this pass runs for.
91const HALF: u32 = 64;
92
93/// How many bytes one half takes in memory, which is how far the high one sits above the low one.
94const STEP: u64 = 8;
95
96/// Whether a type is the width this pass splits.
97fn is_wide(ty: Type) -> bool {
98    ty.is_int() && ty.is_scalar() && ty.bits() == WIDE
99}
100
101/// The type each half has.
102fn half() -> Type {
103    Type::int(HALF)
104}
105
106/// Splits every integer the machine holds in two registers into the two halves it holds it in.
107///
108/// Gives back whether it changed anything, which is what a test asks and what tells a reader of a
109/// dump that the function the selector saw is not the one the middle end produced.
110///
111/// The function is left exactly as it was when there is nothing at that width, when something at
112/// that width is reached by an instruction this does not understand, and when a half would cross
113/// the function's boundary somewhere the convention has no register for it. All three leave the
114/// refusal to the passes below, which name the construct they could not lower, rather than
115/// rewriting into something that guessed.
116pub fn halves(func: &mut Func, names: &mut Interner, conv: &CallRegs) -> bool {
117    if !func.values().any(|value| is_wide(func[value].ty)) {
118        return false;
119    }
120    let insts: Vec<Inst> =
121        walk(func).into_iter().flat_map(|block| func.insts(block).collect::<Vec<_>>()).collect();
122    let order: HashMap<Inst, usize> =
123        insts.iter().enumerate().map(|(at, &inst)| (inst, at)).collect();
124    if !insts.iter().enumerate().all(|(at, &inst)| can_split(func, &order, at, inst)) {
125        return false;
126    }
127    if !func.signatures().all(|signature| fits(signature, conv)) {
128        return false;
129    }
130
131    let mut halves: Halves = HashMap::new();
132    let mut forward: HashMap<Value, Value> = HashMap::new();
133    for block in func.blocks().collect::<Vec<_>>() {
134        params(func, block, &mut halves, &mut forward);
135    }
136    for &inst in &insts {
137        rewrite(func, names, conv.abi, &mut halves, &mut forward, inst);
138    }
139    substitute(func, &forward);
140    let signature = split_signature(func.signature());
141    func.set_signature(signature);
142    true
143}
144
145/// Every block, in an order where a block comes after everything that dominates it.
146///
147/// Reverse postorder from the entry, then whatever the walk did not reach, in the order the
148/// function holds them. The order is what the rule below about a use and its definition is read
149/// against, and the two together are the whole of why this is not simply the order the function
150/// holds the blocks in: a value is defined in a block that dominates every block reading it, a
151/// dominator is on every path from the entry, so a depth first walk finishes it last and reverse
152/// postorder puts it first. The order the function holds blocks in says nothing of the kind. It is
153/// the order they were made in, and every pass in the optimizer that makes a block, which is every
154/// pass that gives a loop a preheader or copies a header in front of one, puts a block that runs
155/// early at the end of that list. So the same program compiled at `-O0` and at `-O1` gave two
156/// different answers to whether this pass understood it, and above `-O0` the answer was often no.
157/// tamnd/rucc#1054.
158///
159/// A block nothing reaches cannot be walked to and is put at the end rather than dropped, because
160/// deciding a block is unreachable is not this pass's business. Two of them in the wrong order
161/// refuse the function the way they always did.
162fn walk(func: &Func) -> Vec<Block> {
163    let Some(entry) = func.entry() else { return func.blocks().collect() };
164    let mut seen: HashSet<Block> = HashSet::new();
165    let mut order: Vec<Block> = Vec::new();
166    // A postorder without recursion: the second time a block comes off the stack every block below
167    // it has been finished, so that is where it belongs in the postorder.
168    let mut stack: Vec<(Block, bool)> = vec![(entry, false)];
169    seen.insert(entry);
170    while let Some((block, done)) = stack.pop() {
171        if done {
172            order.push(block);
173            continue;
174        }
175        stack.push((block, true));
176        let Some(term) = func.terminator(block) else { continue };
177        for call in func.successors(term) {
178            if seen.insert(call.block) {
179                stack.push((call.block, false));
180            }
181        }
182    }
183    order.reverse();
184    order.extend(func.blocks().filter(|block| !seen.contains(block)));
185    order
186}
187
188/// The two halves each wide value became, low first.
189type Halves = HashMap<Value, (Value, Value)>;
190
191/// The opcodes this pass knows how to split.
192///
193/// An instruction that touches a value of this width and is not one of these is why the whole
194/// function is left alone, so this list is the pass's own statement of what it has thought about.
195/// Adding to it is adding an arm to [`rewrite`] as well.
196///
197/// The four divisions and the four conversions to and from a floating point value are here, and they
198/// are the entries that become a call rather than arithmetic over the halves. Which float formats
199/// those conversions are understood at is a separate question, asked in [`can_split`], because it is
200/// about the type rather than about the opcode.
201fn understood(opcode: Opcode) -> bool {
202    matches!(
203        opcode,
204        Opcode::IConst
205            | Opcode::Load
206            | Opcode::Store
207            | Opcode::Add
208            | Opcode::Sub
209            | Opcode::Mul
210            | Opcode::UDiv
211            | Opcode::SDiv
212            | Opcode::URem
213            | Opcode::SRem
214            | Opcode::Shl
215            | Opcode::LShr
216            | Opcode::AShr
217            | Opcode::And
218            | Opcode::Or
219            | Opcode::Xor
220            | Opcode::ICmp
221            | Opcode::Select
222            | Opcode::SIToFP
223            | Opcode::UIToFP
224            | Opcode::FPToSI
225            | Opcode::FPToUI
226            | Opcode::Trunc
227            | Opcode::SExt
228            | Opcode::ZExt
229            | Opcode::Call
230            | Opcode::CallIndirect
231            | Opcode::Return
232            | Opcode::Jump
233            | Opcode::BrIf
234    )
235}
236
237/// Whether one instruction is one this pass can split, given where it is in the walk.
238///
239/// Asked of every instruction, and answered yes at once for the ones that never see a value this
240/// wide, which in a function that has one at all is still most of them.
241fn can_split(func: &Func, order: &HashMap<Inst, usize>, at: usize, inst: Inst) -> bool {
242    let data = func[inst];
243    let reads = operands(func, inst);
244    let wide = |&value: &Value| is_wide(func[value].ty);
245    if !reads.iter().any(wide) && !data.results().any(|value| is_wide(func[value].ty)) {
246        return true;
247    }
248    if !understood(data.opcode) {
249        return false;
250    }
251    // Memory SSA threads a version of memory through each access, and splitting one access into two
252    // makes a version this pass would have to name. Nothing hands this crate a function carrying it
253    // today, and leaving one alone costs less than being wrong about it later.
254    if func.carries_mem(inst) {
255        return false;
256    }
257    // The machine sign extends from a byte and no narrower, so a truth value widened into the high
258    // half would become an instruction with no rule behind it. Zero extending one is fine, which is
259    // why only the signed side is asked about.
260    if data.opcode == Opcode::SExt && reads.iter().any(|&value| func[value].ty.bits() < 8) {
261        return false;
262    }
263    // The runtime has a conversion for a `float`, for a `double` and for a `_Float128`, and for
264    // nothing else, so every other format is refused here rather than turned into a call to a name
265    // nothing defines. An eighty bit float is the one a program reaches without asking for it, since
266    // `long double` is that type on this target, and it is tamnd/rucc#326 rather than an oversight.
267    if matches!(data.opcode, Opcode::SIToFP | Opcode::UIToFP | Opcode::FPToSI | Opcode::FPToUI)
268        && converted(func, inst).is_none()
269    {
270        return false;
271    }
272    // Splitting an argument makes two of them, and which parameter an argument stands for is how a
273    // variadic call knows what the ABI asks of the ones its signature does not name. Two values
274    // where that list has one entry is a call laid out against the wrong list.
275    if matches!(data.opcode, Opcode::Call | Opcode::CallIndirect) {
276        let Extra::Call(info) = data.extra else { return false };
277        if func[func[info].signature].variadic {
278            return false;
279        }
280    }
281    // The halves of a value are written where the value was, so a use this pass reaches before the
282    // definition is a use whose halves do not exist yet. A value arriving as a block parameter is
283    // always ready, since every block's parameters are split before any instruction is.
284    reads.iter().filter(|value| wide(value)).all(|&value| match func[value].def {
285        Def::Result { inst, .. } => order.get(&inst).is_some_and(|&def| def < at),
286        Def::Param { .. } => true,
287    })
288}
289
290/// The format of the floating point side of a conversion, when the runtime has a routine for it.
291///
292/// One float type is in such an instruction, the result of a conversion going up and the operand of
293/// one coming down, so both ends are looked at and the one is found. `None` means the function is
294/// left alone, and it covers a format with no routine, no float at all, and a float on both ends,
295/// which are three shapes that have nothing to be turned into rather than one.
296fn converted(func: &Func, inst: Inst) -> Option<Float> {
297    let data = func[inst];
298    let mut floats = func[data.args]
299        .iter()
300        .copied()
301        .chain(data.results())
302        .map(|value| func[value].ty)
303        .filter(|ty| ty.is_float());
304    let only = floats.next()?;
305    if floats.next().is_some() {
306        return None;
307    }
308    match only.format() {
309        Some(format @ (Float::F32 | Float::F64 | Float::F128)) => Some(format),
310        _ => None,
311    }
312}
313
314/// Everything an instruction reads: its own operands, and the arguments it passes along its edges.
315///
316/// The arguments of a `jump` and of a `br_if` hang on the block call rather than on the
317/// instruction, so an instruction whose own operands are all narrow may still be handing a wide one
318/// to the block it branches to.
319fn operands(func: &Func, inst: Inst) -> Vec<Value> {
320    let mut reads = func[func[inst].args].to_vec();
321    for call in func.successors(inst).collect::<Vec<_>>() {
322        reads.extend_from_slice(&func[call.args]);
323    }
324    reads
325}
326
327/// Whether both halves of every wide parameter of one signature land in registers.
328///
329/// The walk is the one [`crate::abi::entry`] makes, because the answer has to be the one that walk
330/// will give: it hands out places in the order the signature holds the parameters, and a wide
331/// parameter is about to become two halves in a row in that order. Both have to be registers. One
332/// register and one word of the argument area is where two independent words go and is not where
333/// the convention puts a sixteen byte value.
334///
335/// A return value is not asked about. What comes back comes back in the registers a return uses,
336/// which is a sequence of its own with two in it on this convention, and a signature wanting more
337/// than it has is refused by name in [`crate::lower`] already.
338fn fits(signature: &Signature, conv: &CallRegs) -> bool {
339    let mut places = Places::new(conv);
340    for param in &signature.params {
341        // A structure the classification put in the argument area, which is the one parameter whose
342        // place is bytes rather than a register. Everything else is a value, the pointer an `sret`
343        // hands over included, and a value takes the next register of its own kind.
344        if let Abi::ByVal { size, align } = param.abi {
345            places.on_stack(u32::try_from(size).unwrap_or(u32::MAX), align);
346        } else if crate::abi::on_the_stack(param.ty) {
347            let (size, align) = crate::abi::X87_AREA;
348            places.on_stack(size, align);
349        } else if is_wide(param.ty) {
350            let low = places.integer();
351            let high = places.integer();
352            if !matches!((low, high), (Where::Reg(_), Where::Reg(_))) {
353                return false;
354            }
355        } else if param.ty.is_float() {
356            places.float(crate::abi::float_bytes(param.ty));
357        } else {
358            places.integer();
359        }
360    }
361    true
362}
363
364/// One block's parameters, with each wide one replaced by its two halves in the same position.
365///
366/// Every parameter of such a block is made again rather than only the wide ones, because a
367/// parameter's position is its identity to the branches that feed it and appending is the only way
368/// to add one. The narrow ones are made again as themselves and pointed at the copy, which costs
369/// nothing once the substitution below has run.
370fn params(func: &mut Func, block: Block, halves: &mut Halves, forward: &mut HashMap<Value, Value>) {
371    let old: Vec<Value> = func[block].params.clone();
372    if !old.iter().any(|&value| is_wide(func[value].ty)) {
373        return;
374    }
375    for &value in &old {
376        if is_wide(func[value].ty) {
377            let low = func.append_param(block, half());
378            let high = func.append_param(block, half());
379            halves.insert(value, (low, high));
380        } else {
381            let again = func.append_param(block, func[value].ty);
382            forward.insert(value, again);
383        }
384    }
385    func.retain_params(block, |value| !old.contains(&value));
386}
387
388/// One instruction, as instructions over halves.
389fn rewrite(
390    func: &mut Func,
391    names: &mut Interner,
392    abi: &'static AbiDescription,
393    halves: &mut Halves,
394    forward: &mut HashMap<Value, Value>,
395    inst: Inst,
396) {
397    let data = func[inst];
398    let produces = data.results().any(|value| is_wide(func[value].ty));
399    let takes = func[data.args].iter().any(|&value| is_wide(func[value].ty));
400    match data.opcode {
401        Opcode::IConst if produces => constant(func, halves, inst),
402        Opcode::Load if produces => load(func, halves, inst),
403        Opcode::Store if takes => store(func, halves, inst),
404        Opcode::Add | Opcode::Sub if produces => carried(func, halves, inst, data.opcode),
405        Opcode::Mul if produces => multiply(func, halves, inst),
406        Opcode::UDiv | Opcode::SDiv | Opcode::URem | Opcode::SRem if produces => {
407            divide(func, names, abi, halves, inst, data.opcode);
408        }
409        Opcode::Shl | Opcode::LShr | Opcode::AShr if produces => {
410            shifted(func, halves, inst, data.opcode);
411        }
412        Opcode::And | Opcode::Or | Opcode::Xor if produces => {
413            bitwise(func, halves, inst, data.opcode);
414        }
415        Opcode::SIToFP | Opcode::UIToFP if takes => {
416            to_float(func, names, abi, halves, forward, inst, data.opcode == Opcode::SIToFP);
417        }
418        Opcode::FPToSI | Opcode::FPToUI if produces => {
419            from_float(func, names, abi, halves, inst, data.opcode == Opcode::FPToSI);
420        }
421        Opcode::ICmp if takes => compare(func, halves, forward, inst),
422        Opcode::Select if produces => choose(func, halves, inst),
423        Opcode::Trunc if takes => truncate(func, halves, forward, inst),
424        Opcode::SExt | Opcode::ZExt if produces => {
425            extend(func, halves, inst, data.opcode == Opcode::SExt);
426        }
427        Opcode::Call | Opcode::CallIndirect if produces || takes => {
428            call(func, halves, forward, inst);
429        }
430        Opcode::Return if takes => flatten(func, halves, inst),
431        Opcode::Jump | Opcode::BrIf => edges(func, halves, inst),
432        _ => {}
433    }
434}
435
436/// A constant, as the two halves of its bits with the low one first.
437fn constant(func: &mut Func, halves: &mut Halves, inst: Inst) {
438    let Extra::Imm(imm) = func[inst].extra else { return };
439    let bits = func[imm].unsigned();
440    #[expect(clippy::cast_possible_truncation, reason = "the halves are what this is taking")]
441    let (low, high) = (bits as u64, (bits >> HALF) as u64);
442    let low = ahead_const(func, inst, i128::from(low));
443    let high = ahead_const(func, inst, i128::from(high));
444    replace(func, halves, inst, low, high);
445}
446
447/// A read, as the two words of it with the low one first.
448///
449/// Little endian is the order, which is what every target this back end has is. The high word knows
450/// less about its alignment than the low one when the low one knew more than a word, since a
451/// sixteen byte object aligned to sixteen has its high word aligned to eight.
452fn load(func: &mut Func, halves: &mut Halves, inst: Inst) {
453    let data = func[inst];
454    let Extra::Mem(mem) = data.extra else { return };
455    let info = func[mem];
456    let Some(&from) = func[data.args].first() else { return };
457    let low = read(func, inst, from, word(info, 0), data.flags);
458    let up = stepped(func, inst, from);
459    let high = read(func, inst, up, word(info, STEP), data.flags);
460    replace(func, halves, inst, low, high);
461}
462
463/// A write, as the two words of it.
464fn store(func: &mut Func, halves: &mut Halves, inst: Inst) {
465    let data = func[inst];
466    let Extra::Mem(mem) = data.extra else { return };
467    let info = func[mem];
468    let args = func[data.args].to_vec();
469    let [value, into] = args[..] else { return };
470    let Some(&(low, high)) = halves.get(&value) else { return };
471    write(func, inst, low, into, word(info, 0), data.flags);
472    let up = stepped(func, inst, into);
473    write(func, inst, high, up, word(info, STEP), data.flags);
474    func.remove_inst(inst);
475}
476
477/// An add or a subtract, as the same over the low halves and the same again over the high ones with
478/// what the low halves carried between them.
479///
480/// The carry is a comparison and not a flag. An unsigned sum comes out below either operand exactly
481/// when it wrapped, and an unsigned difference wrapped exactly when the left operand was below the
482/// right, which are the two tests [`crate::expand`] writes for the overflow builtins and are what
483/// the machine's own carry flag stands for. Whether the pair is put back together into an `adc` and
484/// an `sbb` is a question for what reads flags rather than for this, and the answer here is correct
485/// either way.
486fn carried(func: &mut Func, halves: &mut Halves, inst: Inst, opcode: Opcode) {
487    let args = func[func[inst].args].to_vec();
488    let [a, b] = args[..] else { return };
489    let (Some(&(a_low, a_high)), Some(&(b_low, b_high))) = (halves.get(&a), halves.get(&b)) else {
490        return;
491    };
492    let low = ahead(func, inst, opcode, &[a_low, b_low]);
493    let carried = if opcode == Opcode::Add {
494        compared(func, inst, IntPred::Ult, low, a_low)
495    } else {
496        compared(func, inst, IntPred::Ult, a_low, b_low)
497    };
498    let carry = ahead(func, inst, Opcode::ZExt, &[carried]);
499    let high = ahead(func, inst, opcode, &[a_high, b_high]);
500    let high = ahead(func, inst, opcode, &[high, carry]);
501    replace(func, halves, inst, low, high);
502}
503
504/// A multiply, which is long multiplication in base two to the sixty fourth with everything that
505/// lands above the width thrown away.
506///
507/// The low half of the answer is the low halves multiplied together. The high half is what that
508/// multiply carried out of its own top, plus the two cross products, each of which starts at bit
509/// sixty four. The fourth partial product is the two high halves against each other and it starts
510/// at bit one hundred and twenty eight, so the whole of it is above the width and it is never
511/// worked out, which is why a wide multiply is three multiplies and not four.
512///
513/// Nothing here asks whether the operands are signed, because the low hundred and twenty eight bits
514/// of a product are the same bits either way. The sign only matters to the bits that are being
515/// thrown away.
516///
517/// The carry out of the low halves is the high half of a sixty four bit product, which this machine
518/// has an instruction for and this compiler has no way to ask for. [`crate::expand`] already writes
519/// that out as long multiplication one level further down, for the overflow builtins, so this calls
520/// it rather than keeping a second copy of the same arithmetic. It is the expensive part of a wide
521/// multiply by a long way, and `tamnd/rucc#309` is the rule that would make it one instruction for
522/// both callers at once.
523fn multiply(func: &mut Func, halves: &mut Halves, inst: Inst) {
524    let args = func[func[inst].args].to_vec();
525    let [a, b] = args[..] else { return };
526    let (Some(&(a_low, a_high)), Some(&(b_low, b_high))) = (halves.get(&a), halves.get(&b)) else {
527        return;
528    };
529    let low = ahead(func, inst, Opcode::Mul, &[a_low, b_low]);
530    let carried = expand::high_half(func, inst, a_low, b_low, false, half());
531    let cross = ahead(func, inst, Opcode::Mul, &[a_low, b_high]);
532    let other = ahead(func, inst, Opcode::Mul, &[a_high, b_low]);
533    let high = ahead(func, inst, Opcode::Add, &[carried, cross]);
534    let high = ahead(func, inst, Opcode::Add, &[high, other]);
535    replace(func, halves, inst, low, high);
536}
537
538/// A divide or a remainder, as a call to the routine in the compiler runtime that works it out.
539///
540/// The four names are libgcc's, and the archive `runtime/builtins/div.c` builds into defines them for
541/// a target that has no libgcc, which is every target this compiler links without gcc's driver. What
542/// picks one of the four is the opcode and nothing else: the sign is in the name because it is in the
543/// answer, since a quotient rounds towards zero and a remainder takes the sign of the dividend, and
544/// neither is the unsigned answer with bits reinterpreted the way a sum is.
545///
546/// The call is created with the halves in it rather than with the wide values, which would then be
547/// split by [`call`] on the next instruction of the walk. Four parameters and two results, in the
548/// order the operands were in and low half first, because that is where the convention puts the two
549/// eightbytes of a value this wide and [`split_signature`] is what the routine's own definition went
550/// through on the way in.
551///
552/// Nothing here is conditional on the divisor. Dividing by zero is undefined in C, the machine traps
553/// on it at every width it has, and a test written in front of the call would be this pass deciding
554/// what an undefined program does.
555fn divide(
556    func: &mut Func,
557    names: &mut Interner,
558    abi: &'static AbiDescription,
559    halves: &mut Halves,
560    inst: Inst,
561    opcode: Opcode,
562) {
563    let args = func[func[inst].args].to_vec();
564    let [a, b] = args[..] else { return };
565    let (Some(&(a_low, a_high)), Some(&(b_low, b_high))) = (halves.get(&a), halves.get(&b)) else {
566        return;
567    };
568    // The four that need the whole value at once, which is why they are calls rather than a pair
569    // of half width instructions like everything else in this pass. Which call each one is, is in
570    // the capability table, since a routine name is a fact about what this target cannot do.
571    let Some(routine) = capability::libcall(opcode, MODE) else { return };
572    let args = [Operand::Split(a_low, a_high), Operand::Split(b_low, b_high)];
573    let made = runtime(func, names, abi, inst, routine, &args, &[half(), half()]);
574    let [low, high] = made[..] else { return };
575    replace(func, halves, inst, low, high);
576}
577
578/// A conversion from one of these to a float, as a call to the routine that works it out.
579///
580/// Two parameters of sixty four bits and one float result. The answer is not a wide value, so the
581/// instruction's own result is pointed at the call's rather than halved, which is what [`compare`]
582/// and [`truncate`] do with a narrow answer as well.
583///
584/// The sign is in the name because it is in the answer: the same hundred and twenty eight bits are
585/// two different numbers depending on it, and unlike a sum the float they become is two different
586/// floats.
587fn to_float(
588    func: &mut Func,
589    names: &mut Interner,
590    abi: &'static AbiDescription,
591    halves: &Halves,
592    forward: &mut HashMap<Value, Value>,
593    inst: Inst,
594    signed: bool,
595) {
596    let Some(&arg) = func[func[inst].args].first() else { return };
597    let Some(&(low, high)) = halves.get(&arg) else { return };
598    let (Some(result), Some(format)) = (func[inst].first_result, converted(func, inst)) else {
599        return;
600    };
601    let routine = going_up(signed, format);
602    let args = [Operand::Split(low, high)];
603    let made = runtime(func, names, abi, inst, routine, &args, &[func[result].ty]);
604    if let [answer] = made[..] {
605        forward.insert(result, answer);
606    }
607    func.remove_inst(inst);
608}
609
610/// A conversion from a float to one of these, as a call to the routine that works it out.
611///
612/// One float parameter and two results of sixty four bits, which is the divide's shape with the
613/// operands and the answer the other way round. The operand is a float and so was never split, and
614/// it is passed along as it is.
615///
616/// A value the integer cannot hold, an infinity and a not a number are all undefined in C, and
617/// nothing is written in front of the call about any of them, for the reason [`divide`] writes
618/// nothing in front of itself about a zero divisor.
619fn from_float(
620    func: &mut Func,
621    names: &mut Interner,
622    abi: &'static AbiDescription,
623    halves: &mut Halves,
624    inst: Inst,
625    signed: bool,
626) {
627    let Some(&arg) = func[func[inst].args].first() else { return };
628    let Some(format) = converted(func, inst) else { return };
629    let routine = coming_down(signed, format);
630    let args = [Operand::Whole(arg)];
631    let made = runtime(func, names, abi, inst, routine, &args, &[half(), half()]);
632    let [low, high] = made[..] else { return };
633    replace(func, halves, inst, low, high);
634}
635
636/// The routine that turns an integer this wide into a float of that format.
637///
638/// Three formats, since [`converted`] answers with no others, and the quad is the last arm rather
639/// than a named one so that a format added to that list arrives here as a routine that does not
640/// exist rather than as a name that is wrong.
641fn going_up(signed: bool, format: Float) -> &'static str {
642    let mode = match format {
643        Float::F32 => "i128.f32",
644        Float::F64 => "i128.f64",
645        _ => "i128.f128",
646    };
647    routine(if signed { Opcode::SIToFP } else { Opcode::UIToFP }, mode)
648}
649
650/// The routine that turns a float of that format into an integer this wide.
651fn coming_down(signed: bool, format: Float) -> &'static str {
652    let mode = match format {
653        Float::F32 => "f32.i128",
654        Float::F64 => "f64.i128",
655        _ => "f128.i128",
656    };
657    routine(if signed { Opcode::FPToSI } else { Opcode::FPToUI }, mode)
658}
659
660/// The routine the capability table names for this operation at this width.
661///
662/// Every mode this pass asks about is one this machine has no register wide enough for, so the
663/// table always has an answer and a missing one is the table and this pass having gone out of step.
664fn routine(opcode: Opcode, mode: &str) -> &'static str {
665    capability::libcall(opcode, mode)
666        .unwrap_or_else(|| panic!("no routine for `{}` at `{mode}`", opcode.name()))
667}
668
669/// One operand of a call to a runtime routine, as this pass has it in hand.
670///
671/// A wide integer is two halves here because two halves is what this pass has turned every one of
672/// them into, and whether the routine is handed the two of them or the address of the one value
673/// they are is the convention's answer rather than this pass's.
674#[derive(Clone, Copy)]
675enum Operand {
676    /// A value of a type the machine holds, given as itself.
677    Whole(Value),
678    /// A wide integer, given as the low half and the high half it became.
679    Split(Value, Value),
680}
681
682/// A call to a routine in the compiler runtime, written in front of an instruction, with the values
683/// it answers.
684///
685/// Where the convention hands everything over in registers the signature is made out of the types
686/// of the values being handed over, because the values are already the halves at this point and the
687/// routine's own definition went through [`split_signature`] on the way in, so the two descriptions
688/// are the same one arrived at from the two ends.
689///
690/// Windows x64 does not hand a value of this width over in registers. A scalar of a size no register
691/// holds travels as the address of a copy the caller made, which is the rule `tamnd/rucc#1331` put
692/// in the ABI description, and it applies to a call this pass writes exactly as it applies to a call
693/// the program wrote: libgcc's `__floattitf` on that target reads its `__int128` out of the address
694/// in `rdx` and writes its answer through the address in `rcx`. So an operand the convention passes
695/// by address becomes a frame slot with a copy of the value in it, a slot per operand because a
696/// routine may write through an address it was handed, and a single answer that comes back by
697/// address becomes a slot passed as the leading `sret` argument with the load out of it standing for
698/// the call's result.
699///
700/// An answer at this width is the third shape and the one that reads strangely. mingw brings a
701/// sixteen byte integer back in `xmm0` rather than through an address, which is gcc's answer to a
702/// convention that has no integer that size in it, so the call is written as returning one value at
703/// the quad float format and the two halves are read back out of a slot it is stored into. The
704/// format is a name for sixteen bytes in a vector register and says nothing about what is in them,
705/// which is the same thing the routine's own `movaps` says.
706fn runtime(
707    func: &mut Func,
708    names: &mut Interner,
709    abi: &'static AbiDescription,
710    inst: Inst,
711    routine: &str,
712    args: &[Operand],
713    results: &[Type],
714) -> Vec<Value> {
715    let mut params: Vec<Param> = Vec::new();
716    let mut values: Vec<Value> = Vec::new();
717    let mut answer = Answer::Registers;
718    // The answer first, because an address it comes back through is the first argument.
719    match *results {
720        [ty] if abi.scalar_is_by_reference(bytes(ty)) => {
721            let size = bytes(ty);
722            let align = align(size);
723            let slot = room(func, inst, size, align);
724            params.push(Param::with_abi(Type::PTR, Abi::Sret { size, align }));
725            values.push(slot);
726            answer = Answer::Slot(slot, ty);
727        }
728        [low, high] if low == half() && high == half() => {
729            if let Some(format) = packed(abi) {
730                answer = Answer::Packed(format);
731            }
732        }
733        _ => {}
734    }
735    for &arg in args {
736        handed(func, abi, inst, arg, &mut params, &mut values);
737    }
738    let answers = match answer {
739        Answer::Registers => results.to_vec(),
740        Answer::Slot(..) => Vec::new(),
741        Answer::Packed(format) => vec![Type::float(format)],
742    };
743    let returns = answers.iter().map(|&ty| Param::new(ty)).collect();
744    let signature = func.add_signature(Signature { params, returns, variadic: false });
745    let callee = Some(names.intern(routine));
746    let varargs = func.push_abis(&[]);
747    let extra = Extra::Call(func.add_call(CallInfo { callee, signature, varargs }));
748    let pushed = func.push_values(&values);
749    let span = func.span(inst);
750    let data = InstData { args: pushed, extra, ..InstData::new(Opcode::Call) };
751    let made = func.create_inst(data, &answers, span);
752    func.insert_before(made, inst);
753    match answer {
754        Answer::Registers => func[made].results().collect(),
755        Answer::Slot(slot, ty) => {
756            let size = bytes(ty);
757            let info = whole(size, align(size));
758            let extra = Extra::Mem(func.add_mem(info));
759            let args = func.push_values(&[slot]);
760            let data = InstData { args, extra, ..InstData::new(Opcode::Load) };
761            vec![written(func, inst, data, ty)]
762        }
763        Answer::Packed(format) => unpacked(func, inst, made, format),
764    }
765}
766
767/// Where the answer of such a call is, once the convention has been asked about it.
768#[derive(Clone, Copy)]
769enum Answer {
770    /// In the registers the signature's own result types name, which is every convention that has
771    /// registers for a value of the width being asked about.
772    Registers,
773    /// In a frame slot whose address went over as the leading `sret` argument, with the type the
774    /// call was meant to answer with.
775    Slot(Value, Type),
776    /// Whole in a vector register, at a format that is this many bytes and is not what is in them.
777    Packed(Float),
778}
779
780/// The format a wide integer answer comes back in on this convention, where it comes back in a
781/// register at all, as the IR spells a format.
782///
783/// [`None`] everywhere but Windows x64. The question is asked of the ABI rather than of the target
784/// name for the reason the rest of this pass asks it there: a second list of which targets do this
785/// is a list that can disagree with the one the classifier reads.
786fn packed(abi: &'static AbiDescription) -> Option<Float> {
787    let format = abi.wide_integer_returns_in(u64::from(WIDE / 8))?;
788    Float::from_bits(format.width())
789}
790
791/// The two halves of an answer that came back whole in a register, read out of a slot it is stored
792/// into.
793///
794/// A store and two loads rather than anything cleverer because the value in hand is at a float
795/// format and the halves wanted are integers, and the frame is the only place this compiler moves
796/// bits between the two files without saying something about them. It is what gcc writes for the
797/// same call.
798fn unpacked(func: &mut Func, inst: Inst, call: Inst, format: Float) -> Vec<Value> {
799    let Some(value) = func[call].first_result else { return Vec::new() };
800    let size = bytes(Type::float(format));
801    let align = align(size);
802    let slot = room(func, inst, size, align);
803    let info = whole(size, align);
804    write(func, inst, value, slot, info, Flags::NONE);
805    let low = read(func, inst, slot, word(info, 0), Flags::NONE);
806    let up = stepped(func, inst, slot);
807    let high = read(func, inst, up, word(info, STEP), Flags::NONE);
808    vec![low, high]
809}
810
811/// One operand of such a call, in the form the convention hands it over in.
812fn handed(
813    func: &mut Func,
814    abi: &'static AbiDescription,
815    inst: Inst,
816    arg: Operand,
817    params: &mut Vec<Param>,
818    values: &mut Vec<Value>,
819) {
820    match arg {
821        Operand::Whole(value) => {
822            let ty = func[value].ty;
823            let size = bytes(ty);
824            if !abi.scalar_is_by_reference(size) {
825                params.push(Param::new(ty));
826                values.push(value);
827                return;
828            }
829            let align = align(size);
830            let slot = room(func, inst, size, align);
831            write(func, inst, value, slot, whole(size, align), Flags::NONE);
832            params.push(Param::new(Type::PTR));
833            values.push(slot);
834        }
835        Operand::Split(low, high) => {
836            let size = u64::from(WIDE / 8);
837            if !abi.scalar_is_by_reference(size) {
838                params.push(Param::new(half()));
839                values.push(low);
840                params.push(Param::new(half()));
841                values.push(high);
842                return;
843            }
844            let align = align(size);
845            let slot = room(func, inst, size, align);
846            let info = whole(size, align);
847            write(func, inst, low, slot, word(info, 0), Flags::NONE);
848            let up = stepped(func, inst, slot);
849            write(func, inst, high, up, word(info, STEP), Flags::NONE);
850            params.push(Param::new(Type::PTR));
851            values.push(slot);
852        }
853    }
854}
855
856/// How many bytes a value of this type takes.
857fn bytes(ty: Type) -> u64 {
858    u64::from(ty.bits().div_ceil(8))
859}
860
861/// How far a value of that size is aligned, which at these sizes is the size itself.
862fn align(size: u64) -> u32 {
863    u32::try_from(size).unwrap_or(u32::MAX)
864}
865
866/// An ordinary access of the whole of one value of that size.
867fn whole(size: u64, align: u32) -> MemInfo {
868    MemInfo {
869        size,
870        align,
871        order: MemOrder::NotAtomic,
872        tbaa: None,
873        owns: 0,
874        restrict: Restrict::NONE,
875    }
876}
877
878/// A frame slot of that size, written in front of an instruction.
879fn room(func: &mut Func, inst: Inst, size: u64, align: u32) -> Value {
880    let extra = Extra::Mem(func.add_mem(whole(size, align)));
881    written(func, inst, InstData { extra, ..InstData::new(Opcode::Alloca) }, Type::PTR)
882}
883
884/// A shift, as each half shifted by the count with the bits that crossed between them put back, and
885/// a second answer for a count that reached a whole half.
886///
887/// A count below sixty four moves each half by the count, and the bits that left one half are the
888/// ones that arrive in the other. A count of sixty four or more empties one half completely, and
889/// what lands in the other is the first half moved by the count less sixty four. Taking the sixty
890/// four bit off a count in range is the same as subtracting sixty four from it, so both cases shift
891/// by the same number of places and differ only in which value ends up where, which means one shift
892/// each and a choice rather than two of everything. The choice is a `select` and not a branch, for
893/// the reason [`choose`] gives.
894///
895/// The bits that cross move the other way by sixty four less the count. That is a shift of sixty
896/// four places when the count is zero, which is not a distance this width has. Moving one place and
897/// then sixty three less the count is the same distance for every count from one to sixty three,
898/// and for a count of zero it shifts a value whose top bit is already gone all the way down to
899/// nothing, which is the right answer: a half that did not move carries nothing into the other one.
900///
901/// A count of a hundred and twenty eight or more is undefined in C and nothing here goes out of its
902/// way about it, the same as at every other width.
903fn shifted(func: &mut Func, halves: &mut Halves, inst: Inst, opcode: Opcode) {
904    let args = func[func[inst].args].to_vec();
905    let [a, b] = args[..] else { return };
906    let (Some(&(a_low, a_high)), Some(&(count, _))) = (halves.get(&a), halves.get(&b)) else {
907        return;
908    };
909    let top = ahead_const(func, inst, i128::from(HALF - 1));
910    let places = ahead(func, inst, Opcode::And, &[count, top]);
911    let back = ahead(func, inst, Opcode::Sub, &[top, places]);
912    let one = ahead_const(func, inst, 1);
913    let zero = ahead_const(func, inst, 0);
914    let bit = ahead_const(func, inst, i128::from(HALF));
915    let reach = ahead(func, inst, Opcode::And, &[count, bit]);
916    let whole = compared(func, inst, IntPred::Ne, reach, zero);
917
918    let (low, high) = if opcode == Opcode::Shl {
919        let moved = ahead(func, inst, Opcode::Shl, &[a_low, places]);
920        let edge = ahead(func, inst, Opcode::LShr, &[a_low, one]);
921        let across = ahead(func, inst, Opcode::LShr, &[edge, back]);
922        let above = ahead(func, inst, Opcode::Shl, &[a_high, places]);
923        let joined = ahead(func, inst, Opcode::Or, &[above, across]);
924        let low = ahead(func, inst, Opcode::Select, &[whole, zero, moved]);
925        let high = ahead(func, inst, Opcode::Select, &[whole, moved, joined]);
926        (low, high)
927    } else {
928        let moved = ahead(func, inst, opcode, &[a_high, places]);
929        let edge = ahead(func, inst, Opcode::Shl, &[a_high, one]);
930        let across = ahead(func, inst, Opcode::Shl, &[edge, back]);
931        let below = ahead(func, inst, Opcode::LShr, &[a_low, places]);
932        let joined = ahead(func, inst, Opcode::Or, &[below, across]);
933        // What is left behind when the whole low half is gone: zeroes for a logical shift, and for
934        // an arithmetic one the sign bit spread over the half it came from.
935        let spent = if opcode == Opcode::AShr {
936            ahead(func, inst, Opcode::AShr, &[a_high, top])
937        } else {
938            zero
939        };
940        let low = ahead(func, inst, Opcode::Select, &[whole, moved, joined]);
941        let high = ahead(func, inst, Opcode::Select, &[whole, spent, moved]);
942        (low, high)
943    };
944    replace(func, halves, inst, low, high);
945}
946
947/// An `and`, an `or` or an `xor`, which is the same operation on each half and nothing between
948/// them.
949fn bitwise(func: &mut Func, halves: &mut Halves, inst: Inst, opcode: Opcode) {
950    let args = func[func[inst].args].to_vec();
951    let [a, b] = args[..] else { return };
952    let (Some(&(a_low, a_high)), Some(&(b_low, b_high))) = (halves.get(&a), halves.get(&b)) else {
953        return;
954    };
955    let low = ahead(func, inst, opcode, &[a_low, b_low]);
956    let high = ahead(func, inst, opcode, &[a_high, b_high]);
957    replace(func, halves, inst, low, high);
958}
959
960/// A comparison, which produces one bit and so is pointed at its answer rather than halved.
961///
962/// An equality is the two halves differing in neither place, which is one `or` over two `xor`s
963/// against zero and is shorter than comparing twice and combining. An ordering is the high halves
964/// settling it outright, or the low halves settling it when the high halves are equal, and the low
965/// halves are compared without a sign because the low half of a signed number is unsigned whatever
966/// the number is.
967///
968/// The high halves are asked a strict question even when the predicate is not strict. A predicate
969/// that lets the two be equal is true of two equal high halves whatever the low halves say, and
970/// what decides it there is the low halves, so `a >= b` is `a.hi > b.hi` or the high halves being
971/// equal and `a.lo >= b.lo` unsigned. Asking `a.hi >= b.hi` instead makes every value with a high
972/// half of its own greater than or equal to every other, which is the shape of this that a
973/// differential run against GCC caught.
974fn compare(func: &mut Func, halves: &Halves, forward: &mut HashMap<Value, Value>, inst: Inst) {
975    let Extra::IntPred(pred) = func[inst].extra else { return };
976    let args = func[func[inst].args].to_vec();
977    let [a, b] = args[..] else { return };
978    let (Some(&(a_low, a_high)), Some(&(b_low, b_high))) = (halves.get(&a), halves.get(&b)) else {
979        return;
980    };
981    let answer = if matches!(pred, IntPred::Eq | IntPred::Ne) {
982        let low = ahead(func, inst, Opcode::Xor, &[a_low, b_low]);
983        let high = ahead(func, inst, Opcode::Xor, &[a_high, b_high]);
984        let both = ahead(func, inst, Opcode::Or, &[low, high]);
985        let zero = ahead_const(func, inst, 0);
986        compared(func, inst, pred, both, zero)
987    } else {
988        let above = compared(func, inst, strict(pred), a_high, b_high);
989        let below = compared(func, inst, unsigned(pred), a_low, b_low);
990        let same = compared(func, inst, IntPred::Eq, a_high, b_high);
991        let tail = bit(func, inst, Opcode::And, same, below);
992        bit(func, inst, Opcode::Or, above, tail)
993    };
994    if let Some(result) = func[inst].first_result {
995        forward.insert(result, answer);
996    }
997    func.remove_inst(inst);
998}
999
1000/// The same ordering with the equal case taken out of it, which is what the high halves are asked.
1001fn strict(pred: IntPred) -> IntPred {
1002    match pred {
1003        IntPred::Sle => IntPred::Slt,
1004        IntPred::Sge => IntPred::Sgt,
1005        IntPred::Ule => IntPred::Ult,
1006        IntPred::Uge => IntPred::Ugt,
1007        other => other,
1008    }
1009}
1010
1011/// The same ordering with no sign in it, which is how the low halves of two signed numbers compare.
1012fn unsigned(pred: IntPred) -> IntPred {
1013    match pred {
1014        IntPred::Slt => IntPred::Ult,
1015        IntPred::Sle => IntPred::Ule,
1016        IntPred::Sgt => IntPred::Ugt,
1017        IntPred::Sge => IntPred::Uge,
1018        other => other,
1019    }
1020}
1021
1022/// A choice between two wide values, which is the same choice made on each half.
1023///
1024/// Two of them rather than one, with the condition read twice. What that costs is one more
1025/// conditional move, and what the alternative costs is a branch, which is the more expensive of the
1026/// two on anything that predicts.
1027fn choose(func: &mut Func, halves: &mut Halves, inst: Inst) {
1028    let args = func[func[inst].args].to_vec();
1029    let [cond, then, other] = args[..] else { return };
1030    let (Some(&(then_low, then_high)), Some(&(other_low, other_high))) =
1031        (halves.get(&then), halves.get(&other))
1032    else {
1033        return;
1034    };
1035    let low = ahead(func, inst, Opcode::Select, &[cond, then_low, other_low]);
1036    let high = ahead(func, inst, Opcode::Select, &[cond, then_high, other_high]);
1037    replace(func, halves, inst, low, high);
1038}
1039
1040/// Keeping the low bits of a wide value, which is the low half and then whatever is left to do.
1041///
1042/// Down to sixty four there is nothing left to do and the low half is the answer, so the truncation
1043/// goes and its readers read the half. Down to anything narrower the machine's own truncation still
1044/// happens, out of the half rather than out of the value that is no longer there.
1045fn truncate(func: &mut Func, halves: &Halves, forward: &mut HashMap<Value, Value>, inst: Inst) {
1046    let Some(&arg) = func[func[inst].args].first() else { return };
1047    let Some(&(low, _)) = halves.get(&arg) else { return };
1048    let Some(result) = func[inst].first_result else { return };
1049    if func[result].ty.bits() == HALF {
1050        forward.insert(result, low);
1051        func.remove_inst(inst);
1052        return;
1053    }
1054    becomes(func, inst, Opcode::Trunc, &[low]);
1055}
1056
1057/// Widening into a wide value, which is the value in the low half and its own sign or zero above.
1058fn extend(func: &mut Func, halves: &mut Halves, inst: Inst, signed: bool) {
1059    let Some(&arg) = func[func[inst].args].first() else { return };
1060    let low = if func[arg].ty.bits() == HALF {
1061        arg
1062    } else {
1063        let opcode = if signed { Opcode::SExt } else { Opcode::ZExt };
1064        ahead(func, inst, opcode, &[arg])
1065    };
1066    let high = if signed {
1067        let top = ahead_const(func, inst, i128::from(HALF - 1));
1068        ahead(func, inst, Opcode::AShr, &[low, top])
1069    } else {
1070        ahead_const(func, inst, 0)
1071    };
1072    replace(func, halves, inst, low, high);
1073}
1074
1075/// A call, as a call passing and receiving halves.
1076///
1077/// The instruction is made again rather than edited, because how many values a call gives back is
1078/// settled when it is created and a wide return value is two where it was one. Its signature is
1079/// made again for the same reason, since the signature is what each end of the call lays itself out
1080/// against and both ends are split the same way.
1081fn call(func: &mut Func, halves: &mut Halves, forward: &mut HashMap<Value, Value>, inst: Inst) {
1082    let data = func[inst];
1083    let Extra::Call(info) = data.extra else { return };
1084    let info = func[info];
1085    let args = spread(&func[data.args], halves);
1086    let results: Vec<Type> = data
1087        .results()
1088        .map(|value| func[value].ty)
1089        .flat_map(|ty| if is_wide(ty) { vec![half(), half()] } else { vec![ty] })
1090        .collect();
1091    let signature = func.add_signature(split_signature(&func[info.signature]));
1092    let extra = Extra::Call(func.add_call(CallInfo { signature, ..info }));
1093    let args = func.push_values(&args);
1094    let span = func.span(inst);
1095    let made = func.create_inst(InstData { args, extra, ..data }, &results, span);
1096    func.insert_before(made, inst);
1097    let mut fresh = func[made].results();
1098    for old in data.results() {
1099        if is_wide(func[old].ty) {
1100            let (Some(low), Some(high)) = (fresh.next(), fresh.next()) else { return };
1101            halves.insert(old, (low, high));
1102        } else if let Some(again) = fresh.next() {
1103            forward.insert(old, again);
1104        }
1105    }
1106    func.remove_inst(inst);
1107}
1108
1109/// A `return`, whose operands are the values the signature says and so are halves now.
1110fn flatten(func: &mut Func, halves: &Halves, inst: Inst) {
1111    let args = spread(&func[func[inst].args], halves);
1112    func[inst].args = func.push_values(&args);
1113}
1114
1115/// A branch, whose arguments hang on the edge rather than on the instruction.
1116fn edges(func: &mut Func, halves: &Halves, inst: Inst) {
1117    for at in func.target_list(inst).iter() {
1118        let call = func[at];
1119        let args = func[call.args].to_vec();
1120        if !args.iter().any(|value| halves.contains_key(value)) {
1121            continue;
1122        }
1123        let args = func.push_values(&spread(&args, halves));
1124        func.set_block_call(at, BlockCall { args, ..call });
1125    }
1126}
1127
1128/// A list of values with each wide one replaced by its two halves in the same position.
1129fn spread(args: &[Value], halves: &Halves) -> Vec<Value> {
1130    args.iter()
1131        .flat_map(|value| match halves.get(value) {
1132            Some(&(low, high)) => vec![low, high],
1133            None => vec![*value],
1134        })
1135        .collect()
1136}
1137
1138/// One signature with every wide parameter and return value as two halves in its place.
1139///
1140/// Each half is plain. What the ABI asks beyond a type is about the bits above a narrow value and
1141/// about an object whose address travels, and a half is neither: it is exactly a register wide and
1142/// it is the value itself.
1143fn split_signature(signature: &Signature) -> Signature {
1144    let split = |params: &[Param]| -> Vec<Param> {
1145        params
1146            .iter()
1147            .flat_map(|param| {
1148                if is_wide(param.ty) {
1149                    vec![Param::new(half()), Param::new(half())]
1150                } else {
1151                    vec![*param]
1152                }
1153            })
1154            .collect()
1155    };
1156    Signature {
1157        params: split(&signature.params),
1158        returns: split(&signature.returns),
1159        variadic: signature.variadic,
1160    }
1161}
1162
1163/// Records the two halves an instruction became and takes the instruction out.
1164fn replace(func: &mut Func, halves: &mut Halves, inst: Inst, low: Value, high: Value) {
1165    if let Some(result) = func[inst].first_result {
1166        halves.insert(result, (low, high));
1167    }
1168    func.remove_inst(inst);
1169}
1170
1171/// Points every reader of a value this pass replaced at what replaced it.
1172///
1173/// The arguments of each instruction and the arguments of the blocks it branches to, which between
1174/// them are everywhere a value can be read. Nothing chases, because every value this map answers
1175/// with is one made here and so is never itself a key.
1176fn substitute(func: &mut Func, forward: &HashMap<Value, Value>) {
1177    if forward.is_empty() {
1178        return;
1179    }
1180    let with = |value: Value| forward.get(&value).copied().unwrap_or(value);
1181    for block in func.blocks().collect::<Vec<_>>() {
1182        for inst in func.insts(block).collect::<Vec<Inst>>() {
1183            let args = func[inst].args;
1184            func.rewrite(args, with);
1185            for call in func.successors(inst).collect::<Vec<_>>() {
1186                func.rewrite(call.args, with);
1187            }
1188        }
1189    }
1190}
1191
1192/// The access one word of a wide access is, that many bytes into it.
1193fn word(info: MemInfo, at: u64) -> MemInfo {
1194    let align = if at == 0 { info.align } else { info.align.min(8) };
1195    MemInfo { size: STEP, align, ..info }
1196}
1197
1198/// The address one word past another, written in front of an instruction.
1199fn stepped(func: &mut Func, inst: Inst, from: Value) -> Value {
1200    let step = ahead_const(func, inst, i128::from(STEP));
1201    let args = func.push_values(&[from, step]);
1202    written(func, inst, InstData { args, ..InstData::new(Opcode::PtrAdd) }, Type::PTR)
1203}
1204
1205/// A load put in front of an instruction, and the half it reads.
1206fn read(func: &mut Func, inst: Inst, from: Value, info: MemInfo, flags: Flags) -> Value {
1207    let extra = Extra::Mem(func.add_mem(info));
1208    let args = func.push_values(&[from]);
1209    let data = InstData { args, flags, extra, ..InstData::new(Opcode::Load) };
1210    written(func, inst, data, half())
1211}
1212
1213/// A store put in front of an instruction, which produces nothing and is only its effect.
1214fn write(func: &mut Func, inst: Inst, value: Value, into: Value, info: MemInfo, flags: Flags) {
1215    let span = func.span(inst);
1216    let extra = Extra::Mem(func.add_mem(info));
1217    let args = func.push_values(&[value, into]);
1218    let data = InstData { args, flags, extra, ..InstData::new(Opcode::Store) };
1219    let made = func.create_inst(data, &[], span);
1220    func.insert_before(made, inst);
1221}
1222
1223/// A comparison written in front of an instruction, which carries its predicate where everything
1224/// else carries nothing.
1225fn compared(func: &mut Func, inst: Inst, pred: IntPred, lhs: Value, rhs: Value) -> Value {
1226    let args = func.push_values(&[lhs, rhs]);
1227    let extra = Extra::IntPred(pred);
1228    written(func, inst, InstData { args, extra, ..InstData::new(Opcode::ICmp) }, Type::I1)
1229}
1230
1231/// An `and` or an `or` over two truth values, which is the same instruction at the width of one.
1232fn bit(func: &mut Func, inst: Inst, opcode: Opcode, lhs: Value, rhs: Value) -> Value {
1233    let args = func.push_values(&[lhs, rhs]);
1234    written(func, inst, InstData { args, ..InstData::new(opcode) }, Type::I1)
1235}
1236
1237/// An instruction over these operands put in front of another one, producing a half.
1238fn ahead(func: &mut Func, inst: Inst, opcode: Opcode, args: &[Value]) -> Value {
1239    let args = func.push_values(args);
1240    written(func, inst, InstData { args, ..InstData::new(opcode) }, half())
1241}
1242
1243/// A constant half put in front of an instruction.
1244fn ahead_const(func: &mut Func, inst: Inst, value: i128) -> Value {
1245    let extra = Extra::Imm(func.add_imm(Imm::int(value, half())));
1246    written(func, inst, InstData { extra, ..InstData::new(Opcode::IConst) }, half())
1247}
1248
1249/// Creates the instruction, puts it in front of another, and reads its value back out.
1250fn written(func: &mut Func, inst: Inst, data: InstData, ty: Type) -> Value {
1251    let span = func.span(inst);
1252    let made = func.create_inst(data, &[ty], span);
1253    func.insert_before(made, inst);
1254    func[made].first_result.expect("an instruction created with one result has one")
1255}
1256
1257/// Turns an instruction into a different one over different operands, in place.
1258fn becomes(func: &mut Func, inst: Inst, opcode: Opcode, args: &[Value]) {
1259    let args = func.push_values(args);
1260    let data = &mut func[inst];
1261    data.opcode = opcode;
1262    data.args = args;
1263    data.extra = Extra::None;
1264    data.flags = data.flags.intersection(Flags::legal_on(opcode));
1265}
1266
1267#[cfg(test)]
1268mod tests {
1269    use rucc_base::Interner;
1270    use rucc_ir::{
1271        Block, Builder, Flags, Float, Func, MemOrder, Module, Restrict, Signature, Type, Value,
1272    };
1273    use rucc_target::x86_64::{MINGW64, SYSV};
1274    use rucc_target::{Arch, Env, Os, TargetInfo, Triple};
1275
1276    use super::{HALF, IntPred, MemInfo, Opcode, halves};
1277
1278    /// The width the pass is about, as a type, which is what every test builds with.
1279    fn wide() -> Type {
1280        Type::int(super::WIDE)
1281    }
1282
1283    fn target() -> TargetInfo {
1284        TargetInfo::new(Triple::new(Arch::X86_64, Os::Linux, Env::Gnu))
1285    }
1286
1287    fn printed(func: &Func, names: &mut Interner) -> String {
1288        let module = Module::new(names.intern("w.c"), &target());
1289        rucc_ir::print_func(&module, func, names)
1290    }
1291
1292    /// A function of those parameters returning that, with its entry block and its parameters.
1293    fn shell(names: &mut Interner, params: &[Type], returns: &[Type]) -> (Func, Block, Vec<Value>) {
1294        let signature = Signature::new().with_params(params).with_returns(returns);
1295        let mut func = Func::new(names.intern("f"), signature);
1296        let entry = func.create_block();
1297        let values = params.iter().map(|&ty| func.append_param(entry, ty)).collect();
1298        (func, entry, values)
1299    }
1300
1301    /// An ordinary access of that many bytes, aligned that far.
1302    fn info(size: u64, align: u32) -> MemInfo {
1303        MemInfo {
1304            size,
1305            align,
1306            order: MemOrder::NotAtomic,
1307            tbaa: None,
1308            owns: 0,
1309            restrict: Restrict::NONE,
1310        }
1311    }
1312
1313    #[test]
1314    fn an_add_carries_from_the_low_half_into_the_high_one() {
1315        let mut names = Interner::new();
1316        let (mut func, entry, params) = shell(&mut names, &[wide(), wide()], &[wide()]);
1317        let mut build = Builder::new(&mut func, entry);
1318        let sum = build.binary(Opcode::Add, params[0], params[1], Flags::NONE);
1319        build.ret(&[sum]);
1320
1321        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1322        let text = printed(&func, &mut names);
1323        assert!(!text.contains("i128"), "nothing that wide is left: {text}");
1324        // Two adds for the halves, one more for the carry, and the carry itself is the unsigned
1325        // comparison that says the low half wrapped.
1326        assert_eq!(text.matches(" = add ").count(), 3, "three adds: {text}");
1327        assert_eq!(text.matches("icmp ult").count(), 1, "one carry: {text}");
1328        assert_eq!(text.matches(" = zext.i64 ").count(), 1, "the carry as a number: {text}");
1329    }
1330
1331    #[test]
1332    fn a_subtract_borrows_the_other_way_round() {
1333        let mut names = Interner::new();
1334        let (mut func, entry, params) = shell(&mut names, &[wide(), wide()], &[wide()]);
1335        let mut build = Builder::new(&mut func, entry);
1336        let difference = build.binary(Opcode::Sub, params[0], params[1], Flags::NONE);
1337        build.ret(&[difference]);
1338
1339        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1340        let text = printed(&func, &mut names);
1341        assert_eq!(text.matches(" = sub ").count(), 3, "three subtracts: {text}");
1342        // The borrow is the operands compared, not the answer, which is what tells a reader the
1343        // two directions were thought about separately.
1344        assert!(text.contains("icmp ult %0, %2"), "the operands are compared: {text}");
1345    }
1346
1347    #[test]
1348    fn the_signature_and_the_entry_block_say_the_same_thing() {
1349        let mut names = Interner::new();
1350        let (mut func, entry, params) = shell(&mut names, &[Type::int(32), wide()], &[wide()]);
1351        let mut build = Builder::new(&mut func, entry);
1352        build.ret(&[params[1]]);
1353
1354        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1355        assert_eq!(
1356            func.signature().param_types().collect::<Vec<_>>(),
1357            [Type::int(32), Type::int(HALF), Type::int(HALF)],
1358            "the wide parameter became two where it stood"
1359        );
1360        assert_eq!(
1361            func.signature().return_types().collect::<Vec<_>>(),
1362            [Type::int(HALF), Type::int(HALF)],
1363            "and so did what comes back"
1364        );
1365        let text = printed(&func, &mut names);
1366        assert!(text.contains("block0(%0: i32, %1: i64, %2: i64)"), "the block agrees: {text}");
1367        assert!(text.contains("return %1, %2"), "both halves go back: {text}");
1368        let _ = entry;
1369    }
1370
1371    #[test]
1372    fn a_read_takes_the_high_word_a_word_above_the_low_one() {
1373        let mut names = Interner::new();
1374        let (mut func, entry, params) = shell(&mut names, &[Type::PTR], &[wide()]);
1375        let mut build = Builder::new(&mut func, entry);
1376        let value = build.load(wide(), params[0], info(16, 16), Flags::NONE);
1377        build.ret(&[value]);
1378
1379        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1380        let text = printed(&func, &mut names);
1381        assert_eq!(text.matches(" = load.i64 ").count(), 2, "two reads: {text}");
1382        assert!(text.contains("ptr_add"), "the high word is a word up: {text}");
1383        // The object is aligned to sixteen and its high word is not, which is the one thing
1384        // splitting an access can get wrong quietly.
1385        assert!(text.contains("align 16"), "the low word keeps what the object had: {text}");
1386        assert!(text.contains("align 8"), "the high word knows less: {text}");
1387    }
1388
1389    #[test]
1390    fn an_equality_asks_once_about_both_halves() {
1391        let mut names = Interner::new();
1392        let (mut func, entry, params) = shell(&mut names, &[wide(), wide()], &[Type::int(32)]);
1393        let mut build = Builder::new(&mut func, entry);
1394        let same = build.icmp(IntPred::Eq, params[0], params[1]);
1395        let answer = build.unary(Opcode::ZExt, same, Type::int(32));
1396        build.ret(&[answer]);
1397
1398        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1399        let text = printed(&func, &mut names);
1400        assert_eq!(text.matches("icmp").count(), 1, "one comparison: {text}");
1401        assert_eq!(text.matches(" = xor ").count(), 2, "the halves differ or they do not: {text}");
1402    }
1403
1404    #[test]
1405    fn an_ordering_reads_the_low_halves_without_a_sign() {
1406        let mut names = Interner::new();
1407        let (mut func, entry, params) = shell(&mut names, &[wide(), wide()], &[Type::int(32)]);
1408        let mut build = Builder::new(&mut func, entry);
1409        let below = build.icmp(IntPred::Slt, params[0], params[1]);
1410        let answer = build.unary(Opcode::ZExt, below, Type::int(32));
1411        build.ret(&[answer]);
1412
1413        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1414        let text = printed(&func, &mut names);
1415        assert!(text.contains("icmp slt"), "the high halves keep the sign: {text}");
1416        assert!(text.contains("icmp ult"), "the low halves have none: {text}");
1417        assert!(
1418            text.contains("icmp eq"),
1419            "and the low halves only matter when the high tie: {text}"
1420        );
1421    }
1422
1423    /// An ordering that allows the two to be equal still asks the high halves a strict question.
1424    ///
1425    /// Two values whose high halves are equal are ordered by their low halves alone, and a high
1426    /// half that is greater than or equal to the other says nothing about that. Asking the high
1427    /// halves the predicate as it stands makes every ordering that is not strict answer yes on a
1428    /// tie, which is the mistake a run against GCC caught.
1429    #[test]
1430    fn an_ordering_that_allows_equality_asks_the_high_halves_a_strict_question() {
1431        let mut names = Interner::new();
1432        let (mut func, entry, params) = shell(&mut names, &[wide(), wide()], &[Type::int(32)]);
1433        let mut build = Builder::new(&mut func, entry);
1434        let at_least = build.icmp(IntPred::Sge, params[0], params[1]);
1435        let answer = build.unary(Opcode::ZExt, at_least, Type::int(32));
1436        build.ret(&[answer]);
1437
1438        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1439        let text = printed(&func, &mut names);
1440        assert!(text.contains("icmp sgt"), "the high halves settle it outright: {text}");
1441        assert!(!text.contains("icmp sge"), "a tie in the high halves settles nothing: {text}");
1442        assert!(text.contains("icmp uge"), "the low halves are the ones allowed to tie: {text}");
1443    }
1444
1445    #[test]
1446    fn a_widening_puts_the_sign_of_the_value_in_the_high_half() {
1447        let mut names = Interner::new();
1448        let (mut func, entry, params) = shell(&mut names, &[Type::int(32)], &[wide()]);
1449        let mut build = Builder::new(&mut func, entry);
1450        let value = build.unary(Opcode::SExt, params[0], wide());
1451        build.ret(&[value]);
1452
1453        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1454        let text = printed(&func, &mut names);
1455        assert!(text.contains("sext.i64"), "the value fills the low half: {text}");
1456        assert!(text.contains("ashr"), "and its sign fills the high one: {text}");
1457    }
1458
1459    #[test]
1460    fn a_block_parameter_becomes_two_and_every_branch_passes_two() {
1461        let mut names = Interner::new();
1462        let (mut func, entry, params) = shell(&mut names, &[wide(), Type::int(32)], &[wide()]);
1463        let tail = func.create_block();
1464        let carried = func.append_param(tail, wide());
1465        let mut build = Builder::new(&mut func, entry);
1466        let zero = build.iconst(Type::int(32), 0);
1467        let taken = build.icmp(IntPred::Ne, params[1], zero);
1468        let other = build.iconst(wide(), 7);
1469        build.br_if(taken, tail, &[params[0]], tail, &[other]);
1470        let mut build = Builder::new(&mut func, tail);
1471        build.ret(&[carried]);
1472
1473        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1474        let text = printed(&func, &mut names);
1475        assert!(!text.contains("i128"), "nothing that wide is left: {text}");
1476        assert!(text.contains("block1(%7: i64, %8: i64)"), "the block takes two: {text}");
1477        assert_eq!(text.matches("block1(").count(), 3, "and both edges pass two: {text}");
1478    }
1479
1480    /// A multiply is the low halves, the two cross products, and nothing for the fourth corner.
1481    ///
1482    /// Three at the top, and four more inside the carry out of the low halves, which is a product
1483    /// at half the width again worked out the same way. What the count is really saying is that the
1484    /// two high halves are never multiplied together, because the whole of that partial product
1485    /// lands above the width.
1486    #[test]
1487    fn a_multiply_is_three_multiplies_and_the_carry_out_of_the_low_ones() {
1488        let mut names = Interner::new();
1489        let (mut func, entry, params) = shell(&mut names, &[wide(), wide()], &[wide()]);
1490        let mut build = Builder::new(&mut func, entry);
1491        let product = build.binary(Opcode::Mul, params[0], params[1], Flags::NONE);
1492        build.ret(&[product]);
1493
1494        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1495        let text = printed(&func, &mut names);
1496        assert!(!text.contains("i128"), "nothing that wide is left: {text}");
1497        assert_eq!(text.matches(" = mul ").count(), 7, "three and the carry's four: {text}");
1498    }
1499
1500    /// Each of the four divisions becomes a call to the routine of that name in the runtime.
1501    ///
1502    /// The sign is in the name because it is in the answer. A quotient rounds towards zero and a
1503    /// remainder takes the sign of the dividend, so the signed routine and the unsigned one work out
1504    /// two different numbers, where a wide add is one computation that two signednesses read the
1505    /// same bits of.
1506    #[test]
1507    fn each_of_the_four_divisions_calls_the_routine_of_that_name() {
1508        for (opcode, routine) in [
1509            (Opcode::UDiv, "__udivti3"),
1510            (Opcode::SDiv, "__divti3"),
1511            (Opcode::URem, "__umodti3"),
1512            (Opcode::SRem, "__modti3"),
1513        ] {
1514            let mut names = Interner::new();
1515            let (mut func, entry, params) = shell(&mut names, &[wide(), wide()], &[wide()]);
1516            let mut build = Builder::new(&mut func, entry);
1517            let answer = build.binary(opcode, params[0], params[1], Flags::NONE);
1518            build.ret(&[answer]);
1519
1520            assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1521            let text = printed(&func, &mut names);
1522            assert!(!text.contains("i128"), "nothing that wide is left: {text}");
1523            assert!(text.contains(&format!("call @{routine}")), "{routine} is called: {text}");
1524        }
1525    }
1526
1527    /// The call hands over four halves and takes two back, which is the shape of the routine.
1528    ///
1529    /// Low half first and the dividend first, which is what the definition of the routine was split
1530    /// into by the same code on the way in. The operands here are the entry block's parameters, so
1531    /// the four values the call passes are the four the block now takes, in order.
1532    #[test]
1533    fn a_divide_hands_over_four_halves_and_takes_two_back() {
1534        let mut names = Interner::new();
1535        let (mut func, entry, params) = shell(&mut names, &[wide(), wide()], &[wide()]);
1536        let mut build = Builder::new(&mut func, entry);
1537        let quotient = build.binary(Opcode::UDiv, params[0], params[1], Flags::NONE);
1538        build.ret(&[quotient]);
1539
1540        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1541        let text = printed(&func, &mut names);
1542        assert!(text.contains("@__udivti3(%0, %1, %2, %3)"), "four halves go over: {text}");
1543        assert!(text.contains("return %4, %5"), "and two come back: {text}");
1544    }
1545
1546    /// A divide whose operands were worked out in the function calls with the halves of those.
1547    ///
1548    /// The other direction of the same rule the walk is for: the call is built where the divide was,
1549    /// so the halves of a sum computed above it exist by then, and what reaches the routine is the
1550    /// two values the sum became rather than anything at the old width.
1551    #[test]
1552    fn a_divide_of_something_computed_calls_with_the_halves_of_it() {
1553        let mut names = Interner::new();
1554        let (mut func, entry, params) = shell(&mut names, &[wide(), wide()], &[wide()]);
1555        let mut build = Builder::new(&mut func, entry);
1556        let sum = build.binary(Opcode::Add, params[0], params[1], Flags::NONE);
1557        let quotient = build.binary(Opcode::SDiv, sum, params[1], Flags::NONE);
1558        build.ret(&[quotient]);
1559
1560        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1561        let text = printed(&func, &mut names);
1562        assert!(!text.contains("i128"), "nothing that wide is left: {text}");
1563        assert_eq!(text.matches(" = add ").count(), 3, "the sum is still a sum: {text}");
1564        assert_eq!(text.matches("call @__divti3").count(), 1, "one call: {text}");
1565    }
1566
1567    /// Each conversion between this width and a float becomes a call to the routine of that name.
1568    ///
1569    /// Twelve of them, which is a signed and an unsigned integer against a `float`, a `double` and a
1570    /// `_Float128` in each direction, and the table is here rather than in a comment because the
1571    /// names are the whole of what this has to get right.
1572    #[test]
1573    fn each_conversion_between_this_width_and_a_float_calls_the_routine_of_that_name() {
1574        let double = Type::float(Float::F64);
1575        let single = Type::float(Float::F32);
1576        let quad = Type::float(Float::F128);
1577        for (opcode, float, routine) in [
1578            (Opcode::SIToFP, double, "__floattidf"),
1579            (Opcode::SIToFP, single, "__floattisf"),
1580            (Opcode::UIToFP, double, "__floatuntidf"),
1581            (Opcode::UIToFP, single, "__floatuntisf"),
1582            (Opcode::SIToFP, quad, "__floattitf"),
1583            (Opcode::UIToFP, quad, "__floatuntitf"),
1584        ] {
1585            let mut names = Interner::new();
1586            let (mut func, entry, params) = shell(&mut names, &[wide()], &[float]);
1587            let mut build = Builder::new(&mut func, entry);
1588            let answer = build.unary(opcode, params[0], float);
1589            build.ret(&[answer]);
1590
1591            assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1592            let text = printed(&func, &mut names);
1593            assert!(!text.contains("i128"), "nothing that wide is left: {text}");
1594            assert!(text.contains(&format!("call @{routine}")), "{routine} is called: {text}");
1595        }
1596        for (opcode, float, routine) in [
1597            (Opcode::FPToSI, double, "__fixdfti"),
1598            (Opcode::FPToSI, single, "__fixsfti"),
1599            (Opcode::FPToUI, double, "__fixunsdfti"),
1600            (Opcode::FPToUI, single, "__fixunssfti"),
1601            (Opcode::FPToSI, quad, "__fixtfti"),
1602            (Opcode::FPToUI, quad, "__fixunstfti"),
1603        ] {
1604            let mut names = Interner::new();
1605            let (mut func, entry, params) = shell(&mut names, &[float], &[wide()]);
1606            let mut build = Builder::new(&mut func, entry);
1607            let answer = build.unary(opcode, params[0], wide());
1608            build.ret(&[answer]);
1609
1610            assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1611            let text = printed(&func, &mut names);
1612            assert!(!text.contains("i128"), "nothing that wide is left: {text}");
1613            assert!(text.contains(&format!("call @{routine}")), "{routine} is called: {text}");
1614        }
1615    }
1616
1617    /// A conversion up hands over two halves and takes one float back, and one coming down is the
1618    /// same call the other way round.
1619    ///
1620    /// The answer going up is not a wide value, so it is one result and the readers of the
1621    /// conversion read it, the way they read the answer of a comparison.
1622    #[test]
1623    fn a_conversion_hands_over_halves_one_way_and_takes_them_back_the_other() {
1624        let double = Type::float(Float::F64);
1625        let mut names = Interner::new();
1626        let (mut func, entry, params) = shell(&mut names, &[wide()], &[double]);
1627        let mut build = Builder::new(&mut func, entry);
1628        let answer = build.unary(Opcode::SIToFP, params[0], double);
1629        build.ret(&[answer]);
1630
1631        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1632        let text = printed(&func, &mut names);
1633        assert!(text.contains("@__floattidf(%0, %1)"), "two halves go over: {text}");
1634        assert!(text.contains("return %2"), "and one float comes back: {text}");
1635
1636        let mut names = Interner::new();
1637        let (mut func, entry, params) = shell(&mut names, &[double], &[wide()]);
1638        let mut build = Builder::new(&mut func, entry);
1639        let answer = build.unary(Opcode::FPToSI, params[0], wide());
1640        build.ret(&[answer]);
1641
1642        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1643        let text = printed(&func, &mut names);
1644        assert!(text.contains("@__fixdfti(%0)"), "the float goes over as it is: {text}");
1645        assert!(text.contains("return %1, %2"), "and two halves come back: {text}");
1646    }
1647
1648    /// A conversion against a quad is that same shape, with the quad crossing whole.
1649    ///
1650    /// Worth its own test because the two sides of it are wide for different reasons. The integer is
1651    /// a pair here because no register holds a hundred and twenty eight bits of integer, and the
1652    /// quad is one value because a vector register holds all of it, so the call this pass writes has
1653    /// two operands and one result going up and one operand and two results coming down.
1654    #[test]
1655    fn a_conversion_against_a_quad_hands_over_the_pair_and_the_quad_whole() {
1656        let quad = Type::float(Float::F128);
1657        let mut names = Interner::new();
1658        let (mut func, entry, params) = shell(&mut names, &[wide()], &[quad]);
1659        let mut build = Builder::new(&mut func, entry);
1660        let answer = build.unary(Opcode::UIToFP, params[0], quad);
1661        build.ret(&[answer]);
1662
1663        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1664        let text = printed(&func, &mut names);
1665        assert!(text.contains("@__floatuntitf(%0, %1)"), "two halves go over: {text}");
1666        assert!(text.contains("return %2"), "and one quad comes back: {text}");
1667
1668        let mut names = Interner::new();
1669        let (mut func, entry, params) = shell(&mut names, &[quad], &[wide()]);
1670        let mut build = Builder::new(&mut func, entry);
1671        let answer = build.unary(Opcode::FPToSI, params[0], wide());
1672        build.ret(&[answer]);
1673
1674        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1675        let text = printed(&func, &mut names);
1676        assert!(text.contains("@__fixtfti(%0)"), "the quad goes over as it is: {text}");
1677        assert!(text.contains("return %1, %2"), "and two halves come back: {text}");
1678    }
1679
1680    /// A conversion at a float width the runtime has no routine for leaves the function alone.
1681    ///
1682    /// `long double` is the eighty bit float on this target and the runtime has no conversion for
1683    /// it, because the back end has no register that holds one, which is tamnd/rucc#326. So the
1684    /// function keeps its wide values and is refused below by name, rather than being turned into a
1685    /// call to a routine nothing defines.
1686    #[test]
1687    fn a_conversion_at_a_width_the_runtime_has_no_routine_for_is_left_alone() {
1688        let long = Type::float(Float::F80);
1689        let mut names = Interner::new();
1690        let (mut func, entry, params) = shell(&mut names, &[wide()], &[long]);
1691        let mut build = Builder::new(&mut func, entry);
1692        let answer = build.unary(Opcode::SIToFP, params[0], long);
1693        build.ret(&[answer]);
1694
1695        assert!(!halves(&mut func, &mut names, &SYSV), "the pass does not understand this one");
1696        let text = printed(&func, &mut names);
1697        assert!(text.contains("i128"), "the width is still there: {text}");
1698    }
1699
1700    /// A shift left moves each half and chooses between the count having crossed a half and not.
1701    ///
1702    /// Two shifts left, one per half, and the low one does for both cases: a count that reached a
1703    /// whole half puts exactly that value in the high half and nothing in the low one, so the only
1704    /// thing the far case needs is the shift the near case already did. Two right shifts carry the
1705    /// crossing bits, two selects pick a half each, and there is no branch anywhere.
1706    #[test]
1707    fn a_shift_left_chooses_between_a_count_that_crossed_a_half_and_one_that_did_not() {
1708        let mut names = Interner::new();
1709        let (mut func, entry, params) = shell(&mut names, &[wide(), wide()], &[wide()]);
1710        let mut build = Builder::new(&mut func, entry);
1711        let moved = build.binary(Opcode::Shl, params[0], params[1], Flags::NONE);
1712        build.ret(&[moved]);
1713
1714        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1715        let text = printed(&func, &mut names);
1716        assert!(!text.contains("i128"), "nothing that wide is left: {text}");
1717        assert_eq!(
1718            text.matches(" = shl ").count(),
1719            2,
1720            "one per half, and the far case reuses one: {text}"
1721        );
1722        assert_eq!(text.matches(" = select.i64 ").count(), 2, "one choice per half: {text}");
1723        assert_eq!(text.matches(" = lshr ").count(), 2, "the crossing bits, in two steps: {text}");
1724    }
1725
1726    /// The bits that cross move one place and then the rest, so a count of zero carries nothing.
1727    ///
1728    /// Sixty four less a count of zero is sixty four, which is not a distance a sixty four bit shift
1729    /// has. One place first and sixty three less the count after is the same distance everywhere the
1730    /// question is asked, and for a count of zero it moves a value whose top bit has already gone
1731    /// all the way out, which leaves the zero a half that did not move should carry.
1732    #[test]
1733    fn the_bits_that_cross_move_one_place_and_then_the_rest_of_the_way() {
1734        let mut names = Interner::new();
1735        let (mut func, entry, params) = shell(&mut names, &[wide(), wide()], &[wide()]);
1736        let mut build = Builder::new(&mut func, entry);
1737        let moved = build.binary(Opcode::LShr, params[0], params[1], Flags::NONE);
1738        build.ret(&[moved]);
1739
1740        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1741        let text = printed(&func, &mut names);
1742        assert!(text.contains("iconst.i64 63"), "sixty three is the distance left: {text}");
1743        assert!(text.contains("iconst.i64 1"), "after the one place that comes first: {text}");
1744        assert!(text.contains(" = sub "), "the rest of the way is worked out: {text}");
1745        assert!(
1746            !text.contains("iconst.i64 127"),
1747            "and the count is not masked to the width: {text}"
1748        );
1749    }
1750
1751    /// An arithmetic shift right leaves the sign bit behind where a logical one leaves zeroes.
1752    ///
1753    /// What the two differ in is only the half the count moved out of entirely. A logical shift puts
1754    /// zeroes there, which is a constant already in hand, and an arithmetic one puts the sign bit
1755    /// spread across the half it came from, which is one more shift.
1756    #[test]
1757    fn an_arithmetic_shift_right_leaves_the_sign_bit_where_a_logical_one_leaves_zeroes() {
1758        let mut names = Interner::new();
1759        let (mut func, entry, params) = shell(&mut names, &[wide(), wide()], &[wide()]);
1760        let mut build = Builder::new(&mut func, entry);
1761        let moved = build.binary(Opcode::AShr, params[0], params[1], Flags::NONE);
1762        build.ret(&[moved]);
1763
1764        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1765        let text = printed(&func, &mut names);
1766        assert!(!text.contains("i128"), "nothing that wide is left: {text}");
1767        // The high half by the count, and the high half by sixty three for the half left empty.
1768        assert_eq!(text.matches(" = ashr ").count(), 2, "the count and the sign: {text}");
1769        assert_eq!(text.matches(" = lshr ").count(), 1, "the low half is not signed: {text}");
1770        assert_eq!(text.matches(" = select.i64 ").count(), 2, "one choice per half: {text}");
1771    }
1772
1773    #[test]
1774    fn a_parameter_with_one_register_left_leaves_the_function_alone() {
1775        let mut names = Interner::new();
1776        let word = Type::int(HALF);
1777        // Five words take five of the six argument registers, so the halves of the sixth
1778        // parameter would be one register and one word of the caller's stack, which is not where
1779        // the convention puts a value this wide.
1780        let params = [word, word, word, word, word, wide()];
1781        let (mut func, entry, values) = shell(&mut names, &params, &[word]);
1782        let mut build = Builder::new(&mut func, entry);
1783        let low = build.unary(Opcode::Trunc, values[5], word);
1784        build.ret(&[low]);
1785        let before = printed(&func, &mut names);
1786
1787        assert!(!halves(&mut func, &mut names, &SYSV), "one of the halves has no register");
1788        assert_eq!(printed(&func, &mut names), before, "so nothing moved");
1789    }
1790
1791    /// The order the function holds its blocks in is not the order they run in.
1792    ///
1793    /// This is what the optimizer produced and `-O0` did not. A block that runs early is made late
1794    /// by whichever pass needed it, so the list the function keeps had a use of a wide value in it
1795    /// before the instruction defining that value, and the walk that asks whether every definition
1796    /// comes first said no and left the whole function alone. Then the selector met an instruction
1797    /// at a width it has no register for and refused the program. The blocks here are made in the
1798    /// order that produces, which is the tail before the middle. tamnd/rucc#1054.
1799    #[test]
1800    fn a_block_made_after_the_one_it_runs_before_is_still_split() {
1801        let mut names = Interner::new();
1802        let (mut func, entry, params) = shell(&mut names, &[wide()], &[wide()]);
1803        let tail = func.create_block();
1804        let middle = func.create_block();
1805        let mut build = Builder::new(&mut func, entry);
1806        build.jump(middle, &[]);
1807        let mut build = Builder::new(&mut func, middle);
1808        let doubled = build.binary(Opcode::Add, params[0], params[0], Flags::NONE);
1809        build.jump(tail, &[]);
1810        let mut build = Builder::new(&mut func, tail);
1811        let again = build.binary(Opcode::Add, doubled, doubled, Flags::NONE);
1812        build.ret(&[again]);
1813
1814        assert!(
1815            halves(&mut func, &mut names, &SYSV),
1816            "the definition runs before the use whatever the list says"
1817        );
1818        let text = printed(&func, &mut names);
1819        assert!(!text.contains("i128"), "nothing that wide is left: {text}");
1820    }
1821
1822    #[test]
1823    fn a_function_with_nothing_that_wide_is_not_touched() {
1824        let mut names = Interner::new();
1825        let word = Type::int(HALF);
1826        let (mut func, entry, params) = shell(&mut names, &[word, word], &[word]);
1827        let mut build = Builder::new(&mut func, entry);
1828        let sum = build.binary(Opcode::Add, params[0], params[1], Flags::NONE);
1829        build.ret(&[sum]);
1830
1831        assert!(!halves(&mut func, &mut names, &SYSV), "there is nothing to split");
1832    }
1833
1834    /// The operands of a runtime call go over the way the target's convention passes them.
1835    ///
1836    /// Windows x64 passes a scalar of a size no register holds as the address of a copy the caller
1837    /// made, so libgcc's `__floattitf` there reads its integer out of the address in `rdx` and
1838    /// writes its answer through the address in `rcx`. Handing it two halves in registers instead is
1839    /// not a worse encoding of the same call, it is a routine reading registers nothing was put in.
1840    #[test]
1841    fn on_windows_a_wide_operand_goes_over_as_the_address_of_a_copy() {
1842        let mut names = Interner::new();
1843        let quad = Type::float(Float::F64);
1844        let (mut func, entry, params) = shell(&mut names, &[wide()], &[quad]);
1845        let mut build = Builder::new(&mut func, entry);
1846        let answer = build.unary(Opcode::SIToFP, params[0], quad);
1847        build.ret(&[answer]);
1848
1849        assert!(halves(&mut func, &mut names, &MINGW64), "there is a width to split");
1850        let text = printed(&func, &mut names);
1851        assert!(text.contains("call @__floattidf"), "{text}");
1852        // One slot with the two halves written into it, and the address of it is the argument.
1853        assert_eq!(text.matches("alloca").count(), 1, "one slot: {text}");
1854        assert_eq!(text.matches("store").count(), 2, "a half at a time: {text}");
1855        assert_eq!(text.matches("ptr_add").count(), 1, "the high half eight bytes up: {text}");
1856        assert!(!text.contains("__floattidf(%0, %1)"), "not the two halves: {text}");
1857    }
1858
1859    /// An answer the convention brings back through an address is the leading argument.
1860    #[test]
1861    fn on_windows_a_wide_answer_at_this_format_comes_back_through_a_slot() {
1862        let mut names = Interner::new();
1863        let quad = Type::float(Float::F128);
1864        let (mut func, entry, params) = shell(&mut names, &[wide()], &[quad]);
1865        let mut build = Builder::new(&mut func, entry);
1866        let answer = build.unary(Opcode::SIToFP, params[0], quad);
1867        build.ret(&[answer]);
1868
1869        assert!(halves(&mut func, &mut names, &MINGW64), "there is a width to split");
1870        let text = printed(&func, &mut names);
1871        assert!(text.contains("call @__floattitf"), "{text}");
1872        // The slot for the answer and the slot for the operand.
1873        assert_eq!(text.matches("alloca").count(), 2, "two slots: {text}");
1874        assert_eq!(text.matches(" = call").count(), 0, "the call answers nothing: {text}");
1875        assert_eq!(text.matches(" = load").count(), 1, "the answer is the load after it: {text}");
1876    }
1877
1878    /// The convention that hands the halves over in registers is left exactly as it was.
1879    #[test]
1880    fn the_convention_with_registers_for_both_halves_puts_nothing_on_the_frame() {
1881        let mut names = Interner::new();
1882        let double = Type::float(Float::F64);
1883        let (mut func, entry, params) = shell(&mut names, &[wide()], &[double]);
1884        let mut build = Builder::new(&mut func, entry);
1885        let answer = build.unary(Opcode::SIToFP, params[0], double);
1886        build.ret(&[answer]);
1887
1888        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1889        let text = printed(&func, &mut names);
1890        assert!(text.contains("@__floattidf(%0, %1)"), "both halves in registers: {text}");
1891        assert!(!text.contains("alloca"), "nothing goes through the frame: {text}");
1892    }
1893
1894    /// An answer at this width on Windows, which comes back whole in a vector register and is taken
1895    /// apart through a slot rather than read out of two of them.
1896    #[test]
1897    fn on_windows_a_wide_answer_comes_back_in_one_register_and_is_split_on_the_frame() {
1898        let mut names = Interner::new();
1899        let (mut func, entry, params) = shell(&mut names, &[wide(), wide()], &[wide()]);
1900        let mut build = Builder::new(&mut func, entry);
1901        let answer = build.binary(Opcode::SDiv, params[0], params[1], Flags::NONE);
1902        build.ret(&[answer]);
1903
1904        assert!(halves(&mut func, &mut names, &MINGW64), "there is a width to split");
1905        let text = printed(&func, &mut names);
1906        // The call answers one value and it is at the quad format, which is the name this compiler
1907        // has for sixteen bytes in a vector register.
1908        assert!(text.contains("call @__divti3(%4, %7) : (ptr, ptr) -> f128"), "{text}");
1909        assert_eq!(text.matches(" = call").count(), 1, "one answer: {text}");
1910        // Two slots for the two operands and one more to take the answer apart in.
1911        assert_eq!(text.matches("alloca").count(), 3, "three slots: {text}");
1912        assert_eq!(text.matches(" = load").count(), 2, "the two halves: {text}");
1913    }
1914
1915    /// The same division where the convention has a pair of registers for the answer.
1916    #[test]
1917    fn the_convention_with_registers_for_the_answer_reads_both_halves_out_of_them() {
1918        let mut names = Interner::new();
1919        let (mut func, entry, params) = shell(&mut names, &[wide(), wide()], &[wide()]);
1920        let mut build = Builder::new(&mut func, entry);
1921        let answer = build.binary(Opcode::SDiv, params[0], params[1], Flags::NONE);
1922        build.ret(&[answer]);
1923
1924        assert!(halves(&mut func, &mut names, &SYSV), "there is a width to split");
1925        let text = printed(&func, &mut names);
1926        assert!(text.contains("@__divti3(%0, %1, %2, %3)"), "four halves over: {text}");
1927        assert!(!text.contains("alloca"), "nothing goes through the frame: {text}");
1928    }
1929}