brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.1 KiB · 0e73ada Raw
252 lines · cpp
1//===-- Target.cpp ----------------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8#include "../Target.h"9#include "AArch64.h"10#include "AArch64RegisterInfo.h"11#include "llvm/CodeGen/MachineInstrBuilder.h"12 13#if defined(__aarch64__) && defined(__linux__)14#include <sys/prctl.h> // For PR_PAC_* constants15#ifndef PR_PAC_APIAKEY16#define PR_PAC_APIAKEY (1UL << 0)17#endif18#ifndef PR_PAC_APIBKEY19#define PR_PAC_APIBKEY (1UL << 1)20#endif21#ifndef PR_PAC_APDAKEY22#define PR_PAC_APDAKEY (1UL << 2)23#endif24#ifndef PR_PAC_APDBKEY25#define PR_PAC_APDBKEY (1UL << 3)26#endif27#endif28 29#define GET_AVAILABLE_OPCODE_CHECKER30#include "AArch64GenInstrInfo.inc"31 32namespace llvm {33namespace exegesis {34 35static unsigned getLoadImmediateOpcode(unsigned RegBitWidth) {36  switch (RegBitWidth) {37  case 32:38    return AArch64::MOVi32imm;39  case 64:40    return AArch64::MOVi64imm;41  }42  llvm_unreachable("Invalid Value Width");43}44 45// Generates instruction to load an immediate value into a register.46static MCInst loadImmediate(MCRegister Reg, unsigned RegBitWidth,47                            const APInt &Value) {48  assert(Value.getBitWidth() <= RegBitWidth &&49         "Value must fit in the Register");50  return MCInstBuilder(getLoadImmediateOpcode(RegBitWidth))51      .addReg(Reg)52      .addImm(Value.getZExtValue());53}54 55static MCInst loadZPRImmediate(MCRegister Reg, unsigned RegBitWidth,56                               const APInt &Value) {57  assert(Value.getZExtValue() < (1 << 7) &&58         "Value must be in the range of the immediate opcode");59  return MCInstBuilder(AArch64::DUP_ZI_D)60      .addReg(Reg)61      .addImm(Value.getZExtValue())62      .addImm(0);63}64 65static MCInst loadPPRImmediate(MCRegister Reg, unsigned RegBitWidth,66                               const APInt &Value) {67  // For PPR, we typically use PTRUE instruction to set predicate registers68  return MCInstBuilder(AArch64::PTRUE_B)69      .addReg(Reg)70      .addImm(31); // All lanes true for 16 bits71}72 73// Generates instructions to load an immediate value into an FPCR register.74static std::vector<MCInst>75loadFPCRImmediate(MCRegister Reg, unsigned RegBitWidth, const APInt &Value) {76  MCRegister TempReg = AArch64::X8;77  MCInst LoadImm = MCInstBuilder(AArch64::MOVi64imm).addReg(TempReg).addImm(0);78  MCInst MoveToFPCR =79      MCInstBuilder(AArch64::MSR).addImm(AArch64SysReg::FPCR).addReg(TempReg);80  return {LoadImm, MoveToFPCR};81}82 83// Fetch base-instruction to load an FP immediate value into a register.84static unsigned getLoadFPImmediateOpcode(unsigned RegBitWidth) {85  switch (RegBitWidth) {86  case 16:87    return AArch64::FMOVH0; // FMOVHi;88  case 32:89    return AArch64::FMOVS0; // FMOVSi;90  case 64:91    return AArch64::MOVID; // FMOVDi;92  case 128:93    return AArch64::MOVIv2d_ns;94  }95  llvm_unreachable("Invalid Value Width");96}97 98// Generates instruction to load an FP immediate value into a register.99static MCInst loadFPImmediate(MCRegister Reg, unsigned RegBitWidth,100                              const APInt &Value) {101  assert(Value.getZExtValue() == 0 && "Expected initialisation value 0");102  MCInst Instructions =103      MCInstBuilder(getLoadFPImmediateOpcode(RegBitWidth)).addReg(Reg);104  if (RegBitWidth >= 64)105    Instructions.addOperand(MCOperand::createImm(Value.getZExtValue()));106  return Instructions;107}108 109#include "AArch64GenExegesis.inc"110 111namespace {112 113// Use X19 as the loop counter register since it's a callee-saved register114// that's available for temporary use.115constexpr MCPhysReg kDefaultLoopCounterReg = AArch64::X19;116 117class ExegesisAArch64Target : public ExegesisTarget {118public:119  ExegesisAArch64Target()120      : ExegesisTarget(AArch64CpuPfmCounters, AArch64_MC::isOpcodeAvailable) {}121 122  Error randomizeTargetMCOperand(const Instruction &Instr, const Variable &Var,123                                 MCOperand &AssignedValue,124                                 const BitVector &ForbiddenRegs) const override;125 126private:127  std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, MCRegister Reg,128                               const APInt &Value) const override {129    if (AArch64::GPR32RegClass.contains(Reg))130      return {loadImmediate(Reg, 32, Value)};131    if (AArch64::GPR64RegClass.contains(Reg))132      return {loadImmediate(Reg, 64, Value)};133    if (AArch64::PPRRegClass.contains(Reg))134      return {loadPPRImmediate(Reg, 16, Value)};135    if (AArch64::FPR8RegClass.contains(Reg))136      return {loadFPImmediate(Reg - AArch64::B0 + AArch64::D0, 64, Value)};137    if (AArch64::FPR16RegClass.contains(Reg))138      return {loadFPImmediate(Reg, 16, Value)};139    if (AArch64::FPR32RegClass.contains(Reg))140      return {loadFPImmediate(Reg, 32, Value)};141    if (AArch64::FPR64RegClass.contains(Reg))142      return {loadFPImmediate(Reg, 64, Value)};143    if (AArch64::FPR128RegClass.contains(Reg))144      return {loadFPImmediate(Reg, 128, Value)};145    if (AArch64::ZPRRegClass.contains(Reg))146      return {loadZPRImmediate(Reg, 128, Value)};147    if (Reg == AArch64::FPCR)148      return {loadFPCRImmediate(Reg, 32, Value)};149 150    errs() << "setRegTo is not implemented, results will be unreliable\n";151    return {};152  }153  MCRegister getDefaultLoopCounterRegister(const Triple &) const override {154    return kDefaultLoopCounterReg;155  }156 157  void decrementLoopCounterAndJump(MachineBasicBlock &MBB,158                                   MachineBasicBlock &TargetMBB,159                                   const MCInstrInfo &MII,160                                   MCRegister LoopRegister) const override {161    // subs LoopRegister, LoopRegister, #1162    BuildMI(&MBB, DebugLoc(), MII.get(AArch64::SUBSXri))163        .addDef(LoopRegister)164        .addUse(LoopRegister)165        .addImm(1)  // Subtract 1166        .addImm(0); // No shift amount167    // b.ne TargetMBB168    BuildMI(&MBB, DebugLoc(), MII.get(AArch64::Bcc))169        .addImm(AArch64CC::NE)170        .addMBB(&TargetMBB);171  }172 173  // Registers that should not be selected for use in snippets.174  const MCPhysReg UnavailableRegisters[1] = {kDefaultLoopCounterReg};175  ArrayRef<MCPhysReg> getUnavailableRegisters() const override {176    return UnavailableRegisters;177  }178 179  bool matchesArch(Triple::ArchType Arch) const override {180    return Arch == Triple::aarch64 || Arch == Triple::aarch64_be;181  }182 183  void addTargetSpecificPasses(PassManagerBase &PM) const override {184    // Function return is a pseudo-instruction that needs to be expanded185    PM.add(createAArch64ExpandPseudoPass());186  }187};188 189Error ExegesisAArch64Target::randomizeTargetMCOperand(190    const Instruction &Instr, const Variable &Var, MCOperand &AssignedValue,191    const BitVector &ForbiddenRegs) const {192  const Operand &Op = Instr.getPrimaryOperand(Var);193  const auto OperandType = Op.getExplicitOperandInfo().OperandType;194  // NOTE: To resolve "Not all operands were initialized by snippet generator"195  // Requires OperandType to be defined for such opcode's operands in AArch64196  // tablegen files. And omit introduced OperandType(s).197 198  // Hacky Fix: Defaulting all OPERAND_UNKNOWN to immediate value 0 works with a199  // limitation that it introduces illegal instruction error for system200  // instructions. System instructions will need to be omitted with OperandType201  // or opcode specific values to avoid generating invalid encodings or202  // unreliable benchmark results for these system-level instructions.203  //  Implement opcode-specific immediate value handling for system instrs:204  //   - MRS/MSR: Use valid system register encodings (e.g., NZCV, FPCR, FPSR)205  //   - MSRpstatesvcrImm1: Use valid PSTATE field encodings (e.g., SPSel,206  //   DAIFSet)207  //   - SYSLxt/SYSxt: Use valid system instruction encodings with proper208  //   CRn/CRm/op values209  //   - UDF: Use valid undefined instruction immediate ranges (0-65535)210 211  switch (OperandType) {212  // MSL (Masking Shift Left) imm operand for 32-bit splatted SIMD constants213  // Correspond to AArch64InstructionSelector::tryAdvSIMDModImm321s()214  case llvm::AArch64::OPERAND_SHIFT_MSL: {215    // There are two valid encodings:216    //   - Type 7: imm at [15:8], [47:40], shift = 264 (0x108) → msl #8217    //   - Type 8: imm at [23:16], [55:48], shift = 272 (0x110) → msl #16218    //     Corresponds AArch64_AM::encodeAdvSIMDModImmType7()219    // But, v2s_msl and v4s_msl instructions accept either form,220    // Thus, Arbitrarily chosing 264 (msl #8) for simplicity.221    AssignedValue = MCOperand::createImm(264);222    return Error::success();223  }224  case llvm::AArch64::OPERAND_IMPLICIT_IMM_0:225    AssignedValue = MCOperand::createImm(0);226    return Error::success();227  case MCOI::OperandType::OPERAND_PCREL:228    AssignedValue = MCOperand::createImm(8);229    return Error::success();230  default:231    break;232  }233 234  return make_error<Failure>(235      Twine("Unimplemented operand type: MCOI::OperandType:")236          .concat(Twine(static_cast<int>(OperandType))));237}238 239} // namespace240 241static ExegesisTarget *getTheExegesisAArch64Target() {242  static ExegesisAArch64Target Target;243  return &Target;244}245 246void InitializeAArch64ExegesisTarget() {247  ExegesisTarget::registerTarget(getTheExegesisAArch64Target());248}249 250} // namespace exegesis251} // namespace llvm252