aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm16/tools/llvm-exegesis/lib/PowerPC/Target.cpp
blob: 54d42dfd22e5f4d328ec11e66fdc3063a28c1294 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//===-- Target.cpp ----------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// The PowerPC ExegesisTarget.
//===----------------------------------------------------------------------===//
#include "../Target.h"
#include "PPC.h"
#include "PPCRegisterInfo.h"

namespace llvm {
namespace exegesis {

// Helper to fill a memory operand with a value.
static void setMemOp(InstructionTemplate &IT, int OpIdx,
                     const MCOperand &OpVal) {
  const auto Op = IT.getInstr().Operands[OpIdx];
  assert(Op.isExplicit() && "invalid memory pattern");
  IT.getValueFor(Op) = OpVal;
}

#include "PPCGenExegesis.inc"

namespace {
class ExegesisPowerPCTarget : public ExegesisTarget {
public:
  ExegesisPowerPCTarget() : ExegesisTarget(PPCCpuPfmCounters) {}

private:
  std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
                               const APInt &Value) const override;
  bool matchesArch(Triple::ArchType Arch) const override {
    return Arch == Triple::ppc64le;
  }
  unsigned getScratchMemoryRegister(const Triple &) const override;
  void fillMemoryOperands(InstructionTemplate &IT, unsigned Reg,
                          unsigned Offset) const override;
};
} // end anonymous namespace

static unsigned getLoadImmediateOpcode(unsigned RegBitWidth) {
  switch (RegBitWidth) {
  case 32:
    return PPC::LI;
  case 64:
    return PPC::LI8;
  }
  llvm_unreachable("Invalid Value Width");
}

// Generates instruction to load an immediate value into a register.
static MCInst loadImmediate(unsigned Reg, unsigned RegBitWidth,
                            const APInt &Value) {
  if (Value.getBitWidth() > RegBitWidth)
    llvm_unreachable("Value must fit in the Register");
  // We don't really care the value in reg, ignore the 16 bit
  // restriction for now.
  // TODO: make sure we get the exact value in reg if needed.
  return MCInstBuilder(getLoadImmediateOpcode(RegBitWidth))
      .addReg(Reg)
      .addImm(Value.getZExtValue());
}

unsigned
ExegesisPowerPCTarget::getScratchMemoryRegister(const Triple &TT) const {
  // R13 is reserved as Thread Pointer, we won't use threading in benchmark, so
  // use it as scratch memory register
  return TT.isArch64Bit() ? PPC::X13 : PPC::R13;
}

void ExegesisPowerPCTarget::fillMemoryOperands(InstructionTemplate &IT,
                                               unsigned Reg,
                                               unsigned Offset) const {
  int MemOpIdx = 0;
  if (IT.getInstr().hasTiedRegisters())
    MemOpIdx = 1;
  int DispOpIdx = MemOpIdx + 1;
  const auto DispOp = IT.getInstr().Operands[DispOpIdx];
  if (DispOp.isReg())
    // We don't really care about the real address in snippets,
    // So hardcode X1 for X-form Memory Operations for simplicity.
    // TODO: materialize the offset into a reggister
    setMemOp(IT, DispOpIdx, MCOperand::createReg(PPC::X1));
  else
    setMemOp(IT, DispOpIdx, MCOperand::createImm(Offset)); // Disp
  setMemOp(IT, MemOpIdx + 2, MCOperand::createReg(Reg));   // BaseReg
}

std::vector<MCInst> ExegesisPowerPCTarget::setRegTo(const MCSubtargetInfo &STI,
                                                    unsigned Reg,
                                                    const APInt &Value) const {
  // X11 is optional use in function linkage, should be the least used one
  // Use it as scratch reg to load immediate.
  unsigned ScratchImmReg = PPC::X11;

  if (PPC::GPRCRegClass.contains(Reg))
    return {loadImmediate(Reg, 32, Value)};
  if (PPC::G8RCRegClass.contains(Reg))
    return {loadImmediate(Reg, 64, Value)};
  if (PPC::F4RCRegClass.contains(Reg))
    return {loadImmediate(ScratchImmReg, 64, Value),
            MCInstBuilder(PPC::MTVSRD).addReg(Reg).addReg(ScratchImmReg)};
  // We don't care the real value in reg, so set 64 bits or duplicate 64 bits
  // for simplicity.
  // TODO: update these if we need a accurate 128 values in registers.
  if (PPC::VRRCRegClass.contains(Reg))
    return {loadImmediate(ScratchImmReg, 64, Value),
            MCInstBuilder(PPC::MTVRD).addReg(Reg).addReg(ScratchImmReg)};
  if (PPC::VSRCRegClass.contains(Reg))
    return {loadImmediate(ScratchImmReg, 64, Value),
            MCInstBuilder(PPC::MTVSRDD)
                .addReg(Reg)
                .addReg(ScratchImmReg)
                .addReg(ScratchImmReg)};
  if (PPC::VFRCRegClass.contains(Reg))
    return {loadImmediate(ScratchImmReg, 64, Value),
            MCInstBuilder(PPC::MTVSRD).addReg(Reg).addReg(ScratchImmReg)};
  // SPE not supported yet
  if (PPC::SPERCRegClass.contains(Reg)) {
    errs() << "Unsupported SPE Reg:" << Reg << "\n";
    return {};
  }
  errs() << "setRegTo is not implemented, results will be unreliable:" << Reg
         << "\n";
  return {};
}

static ExegesisTarget *getTheExegesisPowerPCTarget() {
  static ExegesisPowerPCTarget Target;
  return &Target;
}

void InitializePowerPCExegesisTarget() {
  ExegesisTarget::registerTarget(getTheExegesisPowerPCTarget());
}

} // namespace exegesis
} // namespace llvm