@@ -1589,3 +1589,82 @@ def : CompressPat<(QC_E_BGEUI GPRNoX0:$rs1, uimm5nonzero:$imm5, bare_simm13_lsb0
15891589def : CompressPat<(QC_E_BLTUI GPRNoX0:$rs1, uimm5nonzero:$imm5, bare_simm13_lsb0:$imm12),
15901590 (QC_BLTUI GPRNoX0:$rs1, uimm5nonzero:$imm5, bare_simm13_lsb0:$imm12)>;
15911591} // let isCompressOnly = true, Predicates = [HasVendorXqcibi, IsRV32]
1592+
1593+ // HACKS
1594+ // -----
1595+ // The reasons for needing the definitions below are long and quite annoying. I'm writing
1596+ // this so they are explained in-line, rather than anywhere else.
1597+ //
1598+ // Emitting an instruction to an object proceeds as:
1599+ // - Compression (in emitInstruction)
1600+ // - Emit to Binary Code + Fixups
1601+ // - Assembler Relaxation
1602+ // - Fixup evaluation/application
1603+ // - If relaxed, re-emitted to Binary + Fixups
1604+ // - Relocation generation from Fixups
1605+ //
1606+ // Unfortunately, the `QC.E.LI` -> `C.LI` compression pattern has an edge case that has
1607+ // caused crashes in the past.
1608+ //
1609+ // How the bug happens is:
1610+ // - QC.E.LI is parsed with a bare symbol, which is valid + expected, and can
1611+ // be handled by fixups/relocations.
1612+ // - Compression turns this into a `C.LI` because the `simm6`
1613+ // MCOperandPredicate accepts bare symbols.
1614+ // - Binary Code emission didn't know how to create a fixup for a CI-type
1615+ // instruction containing a bare symbol.
1616+ //
1617+ // The solution to the last bullet is that we added the `fixup_riscv_rvc_imm`,
1618+ // so that we could proceed past the last error, and then use Assembler Relaxation
1619+ // to turn the `C.LI` with a bare symbol back into a `QC.E.LI`.
1620+ //
1621+ // This is good enough for emitting objects, but doesn't work for emitting
1622+ // assembly. Emitting assembly is why we need the following Hacks.
1623+ //
1624+ // Emitting an instruction to assembly proceeds as:
1625+ // - Compression (in emitInstruction)
1626+ // - Decompression (in RISCVInstPrinter::printInst)
1627+ // - InstAliases are applied
1628+ //
1629+ // So in the case of `QC.E.LI` with a bare symbol, first it is compressed to
1630+ // `C.LI` with a bare symbol, and then it is decompressed to `ADDI` with a bare
1631+ // symbol for printing, which is printed via an alias as `li <reg>, <symbol>`.
1632+ // Both the decompression and the alias use the MCOperandPredicate from
1633+ // `simm12`, which accepts bare symbols.
1634+ //
1635+ // The problem here is that `li <reg>, <symbol>` fails to parse, because the
1636+ // parsers do not accept bare symbols, they only accept symbols with specifiers
1637+ // or immediates.
1638+ //
1639+ // Our solution is to add another alias, which will be prioritised above the
1640+ // `li` alias, but only when `qc.e.li` is available. We originally intended to
1641+ // use the `bare_symbol` Operand type, but this had no MCOperandPredicate, and
1642+ // adding one changed the error messages when parsing `qc.e.li` with a
1643+ // too-large constant. So instead, we add a new `AsmOperand` and `Operand` type,
1644+ // just for the alias, which parse just like a BareSymbol, but they
1645+ // have both an MCOperandPredicate, and the error message that corresponds to
1646+ // the existing one on `qc.e.li` for too-large immediates (which fail to parse
1647+ // as both an immediate, and a bare symbol).
1648+ //
1649+ // This is fairly unpleasant, but it's the least disruptive thing we can do
1650+ // and keeps all the hacks confined to the RISC-V backend code.
1651+
1652+ def BareSymbolQC_E_LI : AsmOperandClass {
1653+ let Name = "BareSymbolQC_E_LI";
1654+ let PredicateMethod = "isBareSymbol";
1655+ let RenderMethod = "addImmOperands";
1656+ let DiagnosticType = "InvalidBareSymbolQC_E_LI";
1657+ let ParserMethod = "parseBareSymbol";
1658+ }
1659+
1660+ def hack_bare_symbol_qc_e_li : Operand<XLenVT> {
1661+ let ParserMatchClass = BareSymbolQC_E_LI;
1662+ let MCOperandPredicate = [{
1663+ return MCOp.isExpr() && MCOp.isBareSymbolRef();
1664+ }];
1665+ }
1666+
1667+ let Predicates = [HasVendorXqcili, IsRV32] in {
1668+ def : InstAlias<"qc.e.li $rd, $sym", (ADDI GPR:$rd, X0, hack_bare_symbol_qc_e_li:$sym), 3>;
1669+ } // Predicates = [HasVendorXqcili, IsRV32]
1670+ // END HACKS
0 commit comments