[llvm-branch-commits] [llvm] [4/7][PISA] Add PISA GlobalISel lowering, legalization and combiners (PR #214373)

Kacper Doga via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Sep 14 01:17:14 PDT 2026


================
@@ -0,0 +1,758 @@
+//===-- PISACallLowering.cpp - Call lowering ------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "PISACallLowering.h"
+#include "MCTargetDesc/PISABaseInfo.h"
+#include "PISA.h"
+#include "PISAISelLowering.h"
+#include "PISAMachineFunctionInfo.h"
+#include "PISARegisterInfo.h"
+#include "PISASubtarget.h"
+#include "PISAUtils.h"
+#include "llvm/CodeGen/FunctionLoweringInfo.h"
+#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/Support/ModRef.h"
+
+using namespace llvm;
+
+PISACallLowering::PISACallLowering(const PISATargetLowering &TLI)
+    : CallLowering(&TLI) {}
+
+bool PISACallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
+                                   const Value *Val, ArrayRef<Register> VRegs,
+                                   FunctionLoweringInfo &FLI,
+                                   Register SwiftErrorVReg) const {
+  // FIXME: Currently the return support is only for registers.
+  // Pending:
+  //  - return immediates: fold immediates to return operand
+  if (VRegs.size() > 1)
+    return false;
+  if (Val) {
+    auto &DL = MIRBuilder.getDataLayout();
+    const auto &STI = MIRBuilder.getMF().getSubtarget();
+    unsigned Op = 0;
+    auto *Ty = Val->getType();
+    auto VReg = VRegs[0];
+    if (Ty->isVectorTy()) {
+      auto *VTy = cast<FixedVectorType>(Ty);
+      unsigned NumElts = VTy->getNumElements();
+      unsigned EltSize = DL.getTypeSizeInBits(Ty->getScalarType());
+      switch (EltSize) {
+      case 8:
+        switch (NumElts) {
+        case 2:
+          Op = PISA::retValue_v2i8_r;
+          break;
+        case 3:
+          Op = PISA::retValue_v3i8_r;
+          break;
+        case 4:
+          Op = PISA::retValue_v4i8_r;
+          break;
+        default:
+          llvm_unreachable("Unknown return vector size!");
+          break;
+        }
+        break;
+      case 16:
+        switch (NumElts) {
+        case 2:
+          Op = PISA::retValue_v2i16_r;
+          break;
+        case 3:
+          Op = PISA::retValue_v3i16_r;
+          break;
+        case 4:
+          Op = PISA::retValue_v4i16_r;
+          break;
+        default:
+          llvm_unreachable("Unknown return vector size!");
+          break;
+        }
+        break;
+      case 32:
+        switch (NumElts) {
+        case 2:
+          Op = PISA::retValue_v2i32_r;
+          break;
+        case 3:
+          Op = PISA::retValue_v3i32_r;
+          break;
+        case 4:
+          Op = PISA::retValue_v4i32_r;
+          break;
+        case 5:
+          Op = PISA::retValue_v5i32_r;
+          break;
+        case 6:
+          Op = PISA::retValue_v6i32_r;
+          break;
+        case 7:
+          Op = PISA::retValue_v7i32_r;
+          break;
+        case 8:
+          Op = PISA::retValue_v8i32_r;
+          break;
+        case 16:
+          Op = PISA::retValue_v16i32_r;
+          break;
+        case 32:
+          Op = PISA::retValue_v32i32_r;
+          break;
+        case 64:
+          Op = PISA::retValue_v64i32_r;
+          break;
+        default:
+          llvm_unreachable("Unknown return vector size!");
+          break;
+        }
+        break;
+      case 64:
+        switch (NumElts) {
+        case 2:
+          Op = PISA::retValue_v2i64_r;
+          break;
+        case 3:
+          Op = PISA::retValue_v3i64_r;
+          break;
+        case 4:
+          Op = PISA::retValue_v4i64_r;
+          break;
+        default:
+          llvm_unreachable("Unknown return vector size!");
+          break;
+        }
+        break;
+      default:
+        llvm_unreachable("Unknown return size!");
+        break;
+      }
+    } else {
+      unsigned BitSize = DL.getTypeSizeInBits(Ty);
+      switch (BitSize) {
+      case 1: // change i1 to i16 (see lowerCall())
+      {
+        const LLT I16 = LLT::integer(16);
+        auto Dst = MIRBuilder.getMRI()->createGenericVirtualRegister(I16);
+        auto &MF = MIRBuilder.getMF();
+        auto &F = MF.getFunction();
+        const DataLayout &DL = MF.getDataLayout();
+        ArgInfo RetInfo(VReg, *Val, 0);
+        setArgFlags(RetInfo, AttributeList::ReturnIndex, DL, F);
+        auto Sext = llvm::any_of(
+            RetInfo.Flags, [](const auto &Flag) { return Flag.isSExt(); });
+        auto Zext = llvm::any_of(
+            RetInfo.Flags, [](const auto &Flag) { return Flag.isZExt(); });
+        if (Sext) {
+          MIRBuilder.buildSExt(Dst, VReg);
+        } else if (Zext) {
+          MIRBuilder.buildZExt(Dst, VReg);
+        } else {
+          MIRBuilder.buildAnyExt(Dst, VReg);
+        }
+        VReg = Dst;
+      }
+        Op = PISA::retValue_i16_r;
+        break;
+      case 8:
+        Op = PISA::retValue_i8_r;
+        break;
+      case 16:
+        Op = PISA::retValue_i16_r;
+        break;
+      case 32:
+        Op = PISA::retValue_i32_r;
+        break;
+      case 64:
+        Op = PISA::retValue_i64_r;
+        break;
+      default:
+        llvm_unreachable("Unknown return size!");
+        break;
+      }
+    }
+    // Backend-defined opcodes, e.g. retValue* must have a register
+    // class assigned to their 'source' register. During instruction
+    // combine, a preceeding instructions may be combined, with a new
+    // 'dest' register being assigned. Attempt to replace 'source'
+    // with 'dest' will trigger an assertion in canReplaceReg(), since
+    // there is an expectation of no register class being assigned.
+    // Having an extra copy here eliminates the problem; copy itself
+    // will be removed during instruction selection.
+    auto *MRI = MIRBuilder.getMRI();
+    auto Tmp = MRI->createGenericVirtualRegister(MRI->getType(VReg));
+    MIRBuilder.buildCopy(Tmp, VReg);
+    MIRBuilder.buildInstr(Op).addUse(Tmp).constrainAllUses(
+        MIRBuilder.getTII(), *STI.getRegisterInfo(), *STI.getRegBankInfo());
+    return true;
+  }
+  MIRBuilder.buildInstr(PISA::ret);
+  return true;
+}
+
+bool PISACallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
+                                            const Function &F,
+                                            ArrayRef<ArrayRef<Register>> VRegs,
+                                            FunctionLoweringInfo &FLI) const {
+  auto *MRI = MIRBuilder.getMRI();
+  auto &MF = MIRBuilder.getMF();
+  auto &Ctx = F.getContext();
+  auto *MFInfo = MF.getInfo<PISAMachineFunctionInfo>();
+  auto &DL = F.getParent()->getDataLayout();
+  bool IsKernel = (F.getCallingConv() == CallingConv::PISA_KERNEL);
+  for (const auto [i, Arg] : llvm::enumerate(F.args())) {
+    assert(VRegs[i].size() == 1 && "Formal arg has multiple vregs");
+
+    ArgInfo OrigArg{VRegs[i], Arg, static_cast<unsigned>(i)};
+    setArgFlags(OrigArg, i + AttributeList::FirstArgIndex, DL, F);
+    auto *ArgType = OrigArg.OrigValue->getType();
+    const bool IsByRef = ArgType->isPointerTy() && OrigArg.Flags[0].isByRef();
+    const unsigned ArgSize = IsByRef
+                                 ? OrigArg.Flags[0].getByRefSize()
+                                 : MRI->getType(VRegs[i][0]).getSizeInBytes();
+    MFInfo->setArgInfo(i, ArgSize, IsByRef);
+
+    if (IsKernel && Arg.use_empty())
+      continue;
+
+    unsigned Op = 0;
+    if (IsByRef) {
+      assert(IsKernel && "'byref' is only used in kernel!");
+      Op = PISA::G_PISA_PARAM_SLOT;
+      loadParamWithOpcode(MIRBuilder, F, VRegs[i][0], ArgType, Op,
+                          Arg.getArgNo(), 0);
+    } else if (IsKernel && ArgType->isVectorTy()) {
+      auto *VectorTy = cast<FixedVectorType>(ArgType);
+      auto NumElts = VectorTy->getNumElements();
+      auto *EltTy = VectorTy->getElementType();
+      auto EltSize = DL.getTypeSizeInBits(EltTy);
+      auto Split = (NumElts > 4) || ((NumElts == 3) && (EltSize != 32)) ||
+                   ((NumElts == 4) && (EltSize == 64)) || (NumElts == 1);
+      if (Split) {
+        // handle odd-sized and large kernel args, e.g.
+        //   <3 x i8>                    <16 x i16>
+        //     loadParam_8b @[arg+0]       loadParam_v4_32b @[arg+0]
+        //     loadParam_8b @[arg+1]       loadParam_v4_32b @[arg+16]
+        //     loadParam_8b @[arg+2]       buildVector(<8 x i32>)
+        //     buildVector(<3 x i8>)       bitcast(<16 x i16)
+        auto TargetReg = VRegs[i][0];
+
+        const auto *EltRegClass =
+            (EltSize == 8
+                 ? &PISA::Reg8bRegClass
+                 : (EltSize == 16 ? &PISA::Reg16bRegClass
+                                  : (EltSize == 32 ? &PISA::Reg32bRegClass
+                                                   : &PISA::Reg64bRegClass)));
+        auto TotalSize = NumElts * EltSize;
+        auto EltLLT = LLT::integer(EltSize);
+        auto I32 = LLT::integer(32);
+        if (NumElts <= 4) {
+          // do not group
+        } else if (TotalSize % 128 == 0) { // 4 x i32
+          EltTy = FixedVectorType::get(Type::getInt32Ty(Ctx), 4);
+          EltRegClass = &PISA::RegV4_32bRegClass;
+          EltLLT = LLT::vector(ElementCount::getFixed(4), I32);
+          TargetReg = MRI->createGenericVirtualRegister(
+              LLT::vector(ElementCount::getFixed(TotalSize / 32), I32));
+          NumElts = TotalSize / 128;
+        } else if (TotalSize % 64 == 0) { // 2 x i32
+          EltTy = FixedVectorType::get(Type::getInt32Ty(Ctx), 2);
+          EltRegClass = &PISA::RegV2_32bRegClass;
+          EltLLT = LLT::vector(ElementCount::getFixed(2), I32);
+          TargetReg = MRI->createGenericVirtualRegister(
+              LLT::vector(ElementCount::getFixed(TotalSize / 32), I32));
+          NumElts = TotalSize / 64;
+        } else if (TotalSize % 32 == 0) { // 1 x i32
+          EltTy = Type::getInt32Ty(Ctx);
+          EltRegClass = &PISA::Reg32bRegClass;
+          EltLLT = LLT::integer(32);
+          TargetReg = MRI->createGenericVirtualRegister(
+              LLT::vector(ElementCount::getFixed(TotalSize / 32), I32));
+          NumElts = TotalSize / 32;
+        }
----------------
varev-dev wrote:

```suggestion
        } else if (TotalSize % 32 == 0) { // 1 x i32
          EltTy = Type::getInt32Ty(Ctx);
          EltRegClass = &PISA::Reg32bRegClass;
          EltLLT = LLT::integer(32);
          TargetReg = MRI->createGenericVirtualRegister(
              LLT::scalarOrVector(ElementCount::getFixed(TotalSize / 32), I32));
          NumElts = TotalSize / 32;
        }
```

https://github.com/llvm/llvm-project/pull/214373


More information about the llvm-branch-commits mailing list