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
|