119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//===-- PPCMCCodeEmitter.cpp - Convert PPC code to machine code -----------===//
219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//
319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//                     The LLVM Compiler Infrastructure
419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//
519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman// This file is distributed under the University of Illinois Open Source
619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman// License. See LICENSE.TXT for details.
719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//
819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//===----------------------------------------------------------------------===//
919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//
1019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman// This file implements the PPCMCCodeEmitter class.
1119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//
1219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//===----------------------------------------------------------------------===//
1319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
1419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#define DEBUG_TYPE "mccodeemitter"
1519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "MCTargetDesc/PPCBaseInfo.h"
1619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "MCTargetDesc/PPCFixupKinds.h"
1719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/MC/MCCodeEmitter.h"
1819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/MC/MCInst.h"
1919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/ADT/Statistic.h"
2019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/Support/raw_ostream.h"
2119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/Support/ErrorHandling.h"
2219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanusing namespace llvm;
2319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
2419bac1e08be200c31efd26f0f5fd144c9b3eefd3John BaumanSTATISTIC(MCNumEmitted, "Number of MC instructions emitted");
2519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
2619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumannamespace {
2719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanclass PPCMCCodeEmitter : public MCCodeEmitter {
2819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  PPCMCCodeEmitter(const PPCMCCodeEmitter &); // DO NOT IMPLEMENT
2919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  void operator=(const PPCMCCodeEmitter &);   // DO NOT IMPLEMENT
3019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
3119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanpublic:
3219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  PPCMCCodeEmitter(const MCInstrInfo &mcii, const MCSubtargetInfo &sti,
3319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                   MCContext &ctx) {
3419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  }
3519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
3619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  ~PPCMCCodeEmitter() {}
3719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
3819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  unsigned getDirectBrEncoding(const MCInst &MI, unsigned OpNo,
3919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                               SmallVectorImpl<MCFixup> &Fixups) const;
4019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  unsigned getCondBrEncoding(const MCInst &MI, unsigned OpNo,
4119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                             SmallVectorImpl<MCFixup> &Fixups) const;
4219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  unsigned getHA16Encoding(const MCInst &MI, unsigned OpNo,
4319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                           SmallVectorImpl<MCFixup> &Fixups) const;
4419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  unsigned getLO16Encoding(const MCInst &MI, unsigned OpNo,
4519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                           SmallVectorImpl<MCFixup> &Fixups) const;
4619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  unsigned getMemRIEncoding(const MCInst &MI, unsigned OpNo,
4719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                            SmallVectorImpl<MCFixup> &Fixups) const;
4819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  unsigned getMemRIXEncoding(const MCInst &MI, unsigned OpNo,
4919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                             SmallVectorImpl<MCFixup> &Fixups) const;
5019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  unsigned get_crbitm_encoding(const MCInst &MI, unsigned OpNo,
5119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                               SmallVectorImpl<MCFixup> &Fixups) const;
5219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
5319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  /// getMachineOpValue - Return binary encoding of operand. If the machine
5419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  /// operand requires relocation, record the relocation and return zero.
5519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  unsigned getMachineOpValue(const MCInst &MI,const MCOperand &MO,
5619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                             SmallVectorImpl<MCFixup> &Fixups) const;
5719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
5819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // getBinaryCodeForInstr - TableGen'erated function for getting the
5919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // binary encoding for an instruction.
6019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  unsigned getBinaryCodeForInstr(const MCInst &MI,
6119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                 SmallVectorImpl<MCFixup> &Fixups) const;
6219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
6319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                         SmallVectorImpl<MCFixup> &Fixups) const {
6419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    unsigned Bits = getBinaryCodeForInstr(MI, Fixups);
6519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
6619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    // Output the constant in big endian byte order.
6719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    for (unsigned i = 0; i != 4; ++i) {
6819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      OS << (char)(Bits >> 24);
6919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      Bits <<= 8;
7019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    }
7119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
7219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    ++MCNumEmitted;  // Keep track of the # of mi's emitted.
7319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  }
7419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
7519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman};
7619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
7719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman} // end anonymous namespace
7819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
7919bac1e08be200c31efd26f0f5fd144c9b3eefd3John BaumanMCCodeEmitter *llvm::createPPCMCCodeEmitter(const MCInstrInfo &MCII,
8019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                            const MCSubtargetInfo &STI,
8119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                            MCContext &Ctx) {
8219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return new PPCMCCodeEmitter(MCII, STI, Ctx);
8319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
8419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
8519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanunsigned PPCMCCodeEmitter::
8619bac1e08be200c31efd26f0f5fd144c9b3eefd3John BaumangetDirectBrEncoding(const MCInst &MI, unsigned OpNo,
8719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                    SmallVectorImpl<MCFixup> &Fixups) const {
8819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  const MCOperand &MO = MI.getOperand(OpNo);
8919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO, Fixups);
9019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
9119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // Add a fixup for the branch target.
9219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
9319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                   (MCFixupKind)PPC::fixup_ppc_br24));
9419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return 0;
9519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
9619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
9719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanunsigned PPCMCCodeEmitter::getCondBrEncoding(const MCInst &MI, unsigned OpNo,
9819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                     SmallVectorImpl<MCFixup> &Fixups) const {
9919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  const MCOperand &MO = MI.getOperand(OpNo);
10019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO, Fixups);
10119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
10219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // Add a fixup for the branch target.
10319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
10419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                   (MCFixupKind)PPC::fixup_ppc_brcond14));
10519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return 0;
10619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
10719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
10819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanunsigned PPCMCCodeEmitter::getHA16Encoding(const MCInst &MI, unsigned OpNo,
10919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                       SmallVectorImpl<MCFixup> &Fixups) const {
11019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  const MCOperand &MO = MI.getOperand(OpNo);
11119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO, Fixups);
11219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
11319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // Add a fixup for the branch target.
11419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
11519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                   (MCFixupKind)PPC::fixup_ppc_ha16));
11619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return 0;
11719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
11819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
11919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanunsigned PPCMCCodeEmitter::getLO16Encoding(const MCInst &MI, unsigned OpNo,
12019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                       SmallVectorImpl<MCFixup> &Fixups) const {
12119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  const MCOperand &MO = MI.getOperand(OpNo);
12219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO, Fixups);
12319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
12419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // Add a fixup for the branch target.
12519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
12619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                   (MCFixupKind)PPC::fixup_ppc_lo16));
12719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return 0;
12819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
12919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
13019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanunsigned PPCMCCodeEmitter::getMemRIEncoding(const MCInst &MI, unsigned OpNo,
13119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                            SmallVectorImpl<MCFixup> &Fixups) const {
13219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // Encode (imm, reg) as a memri, which has the low 16-bits as the
13319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // displacement and the next 5 bits as the register #.
13419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  assert(MI.getOperand(OpNo+1).isReg());
13519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups) << 16;
13619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
13719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  const MCOperand &MO = MI.getOperand(OpNo);
13819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  if (MO.isImm())
13919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    return (getMachineOpValue(MI, MO, Fixups) & 0xFFFF) | RegBits;
14019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
14119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // Add a fixup for the displacement field.
14219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
14319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                   (MCFixupKind)PPC::fixup_ppc_lo16));
14419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return RegBits;
14519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
14619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
14719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
14819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanunsigned PPCMCCodeEmitter::getMemRIXEncoding(const MCInst &MI, unsigned OpNo,
14919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                       SmallVectorImpl<MCFixup> &Fixups) const {
15019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // Encode (imm, reg) as a memrix, which has the low 14-bits as the
15119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // displacement and the next 5 bits as the register #.
15219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  assert(MI.getOperand(OpNo+1).isReg());
15319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups) << 14;
15419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
15519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  const MCOperand &MO = MI.getOperand(OpNo);
15619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  if (MO.isImm())
15719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    return (getMachineOpValue(MI, MO, Fixups) & 0x3FFF) | RegBits;
15819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
15919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // Add a fixup for the branch target.
16019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
16119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                   (MCFixupKind)PPC::fixup_ppc_lo14));
16219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return RegBits;
16319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
16419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
16519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
16619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanunsigned PPCMCCodeEmitter::
16719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanget_crbitm_encoding(const MCInst &MI, unsigned OpNo,
16819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                    SmallVectorImpl<MCFixup> &Fixups) const {
16919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  const MCOperand &MO = MI.getOperand(OpNo);
17019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  assert((MI.getOpcode() == PPC::MTCRF || MI.getOpcode() == PPC::MFOCRF) &&
17119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman         (MO.getReg() >= PPC::CR0 && MO.getReg() <= PPC::CR7));
17219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return 0x80 >> getPPCRegisterNumbering(MO.getReg());
17319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
17419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
17519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
17619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanunsigned PPCMCCodeEmitter::
17719bac1e08be200c31efd26f0f5fd144c9b3eefd3John BaumangetMachineOpValue(const MCInst &MI, const MCOperand &MO,
17819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                  SmallVectorImpl<MCFixup> &Fixups) const {
17919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  if (MO.isReg()) {
18019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    // MTCRF/MFOCRF should go through get_crbitm_encoding for the CR operand.
18119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    // The GPR operand should come through here though.
18219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    assert((MI.getOpcode() != PPC::MTCRF && MI.getOpcode() != PPC::MFOCRF) ||
18319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman           MO.getReg() < PPC::CR0 || MO.getReg() > PPC::CR7);
18419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    return getPPCRegisterNumbering(MO.getReg());
18519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  }
18619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
18719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  assert(MO.isImm() &&
18819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman         "Relocation required in an instruction that we cannot encode!");
18919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return MO.getImm();
19019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
19119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
19219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
19319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "PPCGenMCCodeEmitter.inc"
194