brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.2 KiB · 5668e85 Raw
180 lines · cpp
1//===-------------- BPFMIChecking.cpp - MI Checking Legality -------------===//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//9// This pass performs checking to signal errors for certain illegal usages at10// MachineInstruction layer. Specially, the result of XADD{32,64} insn should11// not be used. The pass is done at the PreEmit pass right before the12// machine code is emitted at which point the register liveness information13// is still available.14//15//===----------------------------------------------------------------------===//16 17#include "BPF.h"18#include "BPFTargetMachine.h"19#include "llvm/CodeGen/MachineFunctionPass.h"20#include "llvm/IR/DiagnosticInfo.h"21#include "llvm/Support/Debug.h"22 23using namespace llvm;24 25#define DEBUG_TYPE "bpf-mi-checking"26 27namespace {28 29struct BPFMIPreEmitChecking : public MachineFunctionPass {30 31  static char ID;32  MachineFunction *MF;33  const TargetRegisterInfo *TRI;34 35  BPFMIPreEmitChecking() : MachineFunctionPass(ID) {}36 37private:38  // Initialize class variables.39  void initialize(MachineFunction &MFParm);40 41  void processAtomicInsts();42 43public:44  // Main entry point for this pass.45  bool runOnMachineFunction(MachineFunction &MF) override {46    if (!skipFunction(MF.getFunction())) {47      initialize(MF);48      processAtomicInsts();49    }50    return false;51  }52};53 54// Initialize class variables.55void BPFMIPreEmitChecking::initialize(MachineFunction &MFParm) {56  MF = &MFParm;57  TRI = MF->getSubtarget<BPFSubtarget>().getRegisterInfo();58  LLVM_DEBUG(dbgs() << "*** BPF PreEmit checking pass ***\n\n");59}60 61// Make sure all Defs of XADD are dead, meaning any result of XADD insn is not62// used.63//64// NOTE: BPF backend hasn't enabled sub-register liveness track, so when the65// source and destination operands of XADD are GPR32, there is no sub-register66// dead info. If we rely on the generic MachineInstr::allDefsAreDead, then we67// will raise false alarm on GPR32 Def.68//69// To support GPR32 Def, ideally we could just enable sub-registr liveness track70// on BPF backend, then allDefsAreDead could work on GPR32 Def. This requires71// implementing TargetSubtargetInfo::enableSubRegLiveness on BPF.72//73// However, sub-register liveness tracking module inside LLVM is actually74// designed for the situation where one register could be split into more than75// one sub-registers for which case each sub-register could have their own76// liveness and kill one of them doesn't kill others. So, tracking liveness for77// each make sense.78//79// For BPF, each 64-bit register could only have one 32-bit sub-register. This80// is exactly the case which LLVM think brings no benefits for doing81// sub-register tracking, because the live range of sub-register must always82// equal to its parent register, therefore liveness tracking is disabled even83// the back-end has implemented enableSubRegLiveness. The detailed information84// is at r232695:85//86//   Author: Matthias Braun <matze@braunis.de>87//   Date:   Thu Mar 19 00:21:58 2015 +000088//   Do not track subregister liveness when it brings no benefits89//90// Hence, for BPF, we enhance MachineInstr::allDefsAreDead. Given the solo91// sub-register always has the same liveness as its parent register, LLVM is92// already attaching a implicit 64-bit register Def whenever the there is93// a sub-register Def. The liveness of the implicit 64-bit Def is available.94// For example, for "lock *(u32 *)(r0 + 4) += w9", the MachineOperand info could95// be:96//97//   $w9 = XADDW32 killed $r0, 4, $w9(tied-def 0),98//                        implicit killed $r9, implicit-def dead $r999//100// Even though w9 is not marked as Dead, the parent register r9 is marked as101// Dead correctly, and it is safe to use such information or our purpose.102static bool hasLiveDefs(const MachineInstr &MI, const TargetRegisterInfo *TRI) {103  const MCRegisterClass *GPR64RegClass =104      &BPFMCRegisterClasses[BPF::GPRRegClassID];105  std::vector<unsigned> GPR32LiveDefs;106  std::vector<unsigned> GPR64DeadDefs;107 108  for (const MachineOperand &MO : MI.operands()) {109    bool RegIsGPR64;110 111    if (!MO.isReg() || MO.isUse())112      continue;113 114    RegIsGPR64 = GPR64RegClass->contains(MO.getReg());115    if (!MO.isDead()) {116      // It is a GPR64 live Def, we are sure it is live.117      if (RegIsGPR64)118        return true;119      // It is a GPR32 live Def, we are unsure whether it is really dead due to120      // no sub-register liveness tracking. Push it to vector for deferred121      // check.122      GPR32LiveDefs.push_back(MO.getReg());123      continue;124    }125 126    // Record any GPR64 dead Def as some unmarked GPR32 could be alias of its127    // low 32-bit.128    if (RegIsGPR64)129      GPR64DeadDefs.push_back(MO.getReg());130  }131 132  // No GPR32 live Def, safe to return false.133  if (GPR32LiveDefs.empty())134    return false;135 136  // No GPR64 dead Def, so all those GPR32 live Def can't have alias, therefore137  // must be truely live, safe to return true.138  if (GPR64DeadDefs.empty())139    return true;140 141  // Otherwise, return true if any aliased SuperReg of GPR32 is not dead.142  for (auto I : GPR32LiveDefs)143    for (MCPhysReg SR : TRI->superregs(I))144      if (!llvm::is_contained(GPR64DeadDefs, SR))145        return true;146 147  return false;148}149 150void BPFMIPreEmitChecking::processAtomicInsts() {151  if (MF->getSubtarget<BPFSubtarget>().getHasJmp32())152    return;153 154  // Only check for cpu version 1 and 2.155  for (MachineBasicBlock &MBB : *MF) {156    for (MachineInstr &MI : MBB) {157      if (MI.getOpcode() != BPF::XADDW && MI.getOpcode() != BPF::XADDD)158        continue;159 160      LLVM_DEBUG(MI.dump());161      if (hasLiveDefs(MI, TRI)) {162        const DebugLoc &DL = MI.getDebugLoc();163        const Function &F = MF->getFunction();164        F.getContext().diagnose(DiagnosticInfoUnsupported{165            F, "Invalid usage of the XADD return value", DL});166      }167    }168  }169}170 171} // namespace172 173INITIALIZE_PASS(BPFMIPreEmitChecking, "bpf-mi-pemit-checking",174                "BPF PreEmit Checking", false, false)175 176char BPFMIPreEmitChecking::ID = 0;177FunctionPass *llvm::createBPFMIPreEmitCheckingPass() {178  return new BPFMIPreEmitChecking();179}180