98 changes: 98 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//===-- llvm/CodeGen/GlobalISel/MachineLegalizeHelper.cpp -----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file This file implements the MachineLegalizeHelper class to legalize
/// individual instructions and the LegalizeMachineIR wrapper pass for the
/// primary legalization.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/GlobalISel/MachineLegalizeHelper.h"
#include "llvm/CodeGen/GlobalISel/MachineLegalizer.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetSubtargetInfo.h"

#include <sstream>

#define DEBUG_TYPE "legalize-mir"

using namespace llvm;

MachineLegalizeHelper::MachineLegalizeHelper(MachineFunction &MF)
: MRI(MF.getRegInfo()) {
MIRBuilder.setMF(MF);
}

MachineLegalizeHelper::LegalizeResult MachineLegalizeHelper::legalizeInstr(
MachineInstr &MI, const MachineLegalizer &Legalizer) {
auto Action = Legalizer.getAction(MI);
switch (Action.first) {
case MachineLegalizer::Legal:
return AlreadyLegal;
case MachineLegalizer::NarrowScalar:
return narrowScalar(MI, Action.second);
case MachineLegalizer::WidenScalar:
return widenScalar(MI, Action.second);
case MachineLegalizer::FewerElements:
return fewerElementsVector(MI, Action.second);
default:
return UnableToLegalize;
}
}

void MachineLegalizeHelper::extractParts(unsigned Reg, LLT Ty, int NumParts,
SmallVectorImpl<unsigned> &VRegs) {
unsigned Size = Ty.getSizeInBits();
SmallVector<unsigned, 4> Indexes;
for (int i = 0; i < NumParts; ++i) {
VRegs.push_back(MRI.createGenericVirtualRegister(Size));
Indexes.push_back(i * Size);
}
MIRBuilder.buildExtract(Ty, VRegs, Reg, Indexes);
}

MachineLegalizeHelper::LegalizeResult
MachineLegalizeHelper::narrowScalar(MachineInstr &MI, LLT NarrowTy) {
return UnableToLegalize;
}

MachineLegalizeHelper::LegalizeResult
MachineLegalizeHelper::widenScalar(MachineInstr &MI, LLT WideTy) {
return UnableToLegalize;
}

MachineLegalizeHelper::LegalizeResult
MachineLegalizeHelper::fewerElementsVector(MachineInstr &MI, LLT NarrowTy) {
switch (MI.getOpcode()) {
default:
return UnableToLegalize;
case TargetOpcode::G_ADD: {
unsigned NarrowSize = NarrowTy.getSizeInBits();
int NumParts = MI.getType().getSizeInBits() / NarrowSize;

MIRBuilder.setInstr(MI);

SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs;
extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs);
extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs);

for (int i = 0; i < NumParts; ++i) {
unsigned DstReg = MRI.createGenericVirtualRegister(NarrowSize);
MIRBuilder.buildAdd(NarrowTy, DstReg, Src1Regs[i], Src2Regs[i]);
DstRegs.push_back(DstReg);
}

MIRBuilder.buildSequence(MI.getType(), MI.getOperand(0).getReg(), DstRegs);
MI.eraseFromParent();
return Legalized;
}
}
}
72 changes: 72 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/MachineLegalizePass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//===-- llvm/CodeGen/GlobalISel/MachineLegalizePass.cpp -------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file This file implements the LegalizeHelper class to legalize individual
/// instructions and the MachineLegalizePass wrapper pass for the primary
/// legalization.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/GlobalISel/MachineLegalizePass.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/GlobalISel/MachineLegalizeHelper.h"
#include "llvm/CodeGen/GlobalISel/MachineLegalizer.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetSubtargetInfo.h"

#define DEBUG_TYPE "legalize-mir"

using namespace llvm;

char MachineLegalizePass::ID = 0;
INITIALIZE_PASS(MachineLegalizePass, DEBUG_TYPE,
"Legalize the Machine IR a function's Machine IR", false,
false);

MachineLegalizePass::MachineLegalizePass() : MachineFunctionPass(ID) {
initializeMachineLegalizePassPass(*PassRegistry::getPassRegistry());
}

void MachineLegalizePass::init(MachineFunction &MF) {
}

bool MachineLegalizePass::runOnMachineFunction(MachineFunction &MF) {
DEBUG(dbgs() << "Legalize Machine IR for: " << MF.getName() << '\n');
init(MF);
const MachineLegalizer &Legalizer = *MF.getSubtarget().getMachineLegalizer();
MachineLegalizeHelper Helper(MF);

// FIXME: an instruction may need more than one pass before it is legal. For
// example on most architectures <3 x i3> is doubly-illegal. It would
// typically proceed along a path like: <3 x i3> -> <3 x i8> -> <8 x i8>. We
// probably want a worklist of instructions rather than naive iterate until
// convergence for performance reasons.
bool Changed = false;
MachineBasicBlock::iterator NextMI;
for (auto &MBB : MF)
for (auto MI = MBB.begin(); MI != MBB.end(); MI = NextMI) {
// Get the next Instruction before we try to legalize, because there's a
// good chance MI will be deleted.
NextMI = std::next(MI);
auto Res = Helper.legalizeInstr(*MI, Legalizer);

// Error out if we couldn't legalize this instruction. We may want to fall
// back to DAG ISel instead in the future.
if (Res == MachineLegalizeHelper::UnableToLegalize) {
std::string Msg;
raw_string_ostream OS(Msg);
OS << "unable to legalize instruction: ";
MI->print(OS);
report_fatal_error(OS.str());
}

Changed |= Res == MachineLegalizeHelper::Legalized;
}
return Changed;
}
9 changes: 5 additions & 4 deletions llvm/lib/CodeGen/GlobalISel/MachineLegalizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ MachineLegalizer::MachineLegalizer() : TablesInitialized(false) {
DefaultActions[TargetOpcode::G_ADD] = NarrowScalar;
}

bool MachineLegalizer::legalizeInstr(MachineInstr &MI) const {
llvm_unreachable("Unimplemented functionality");
}

void MachineLegalizer::computeTables() {
for (auto &Op : Actions) {
LLT Ty = Op.first.second;
Expand All @@ -56,6 +52,11 @@ MachineLegalizer::getAction(unsigned Opcode, LLT Ty) const {
// These *have* to be implemented for now, they're the fundamental basis of
// how everything else is transformed.

// FIXME: the long-term plan calls for expansion in terms of load/store (if
// they're not legal).
if (Opcode == TargetOpcode::G_SEQUENCE || Opcode == TargetOpcode::G_EXTRACT)
return std::make_pair(Legal, Ty);

auto ActionIt = Actions.find(std::make_pair(Opcode, Ty));
if (ActionIt != Actions.end())
return findLegalAction(Opcode, Ty, ActionIt->second);
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/CodeGen/LLVMTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ addPassesToGenerateCode(LLVMTargetMachine *TM, PassManagerBase &PM,
if (PassConfig->addIRTranslator())
return nullptr;

PassConfig->addPreLegalizeMachineIR();

if (PassConfig->addLegalizeMachineIR())
return nullptr;

// Before running the register bank selector, ask the target if it
// wants to run some passes.
PassConfig->addPreRegBankSelect();
Expand Down
30 changes: 30 additions & 0 deletions llvm/lib/Target/AArch64/AArch64MachineLegalizer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//===- AArch64MachineLegalizer.cpp -------------------------------*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// This file implements the targeting of the Machinelegalizer class for
/// AArch64.
/// \todo This should be generated by TableGen.
//===----------------------------------------------------------------------===//

#include "AArch64MachineLegalizer.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/Target/TargetOpcodes.h"

using namespace llvm;

#ifndef LLVM_BUILD_GLOBAL_ISEL
#error "You shouldn't build this"
#endif

AArch64MachineLegalizer::AArch64MachineLegalizer() {
setAction(TargetOpcode::G_ADD, LLT::vector(2, 64), Legal);
computeTables();
}
30 changes: 30 additions & 0 deletions llvm/lib/Target/AArch64/AArch64MachineLegalizer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//===- AArch64Machinelegalizer --------------------------------*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// This file declares the targeting of the Machinelegalizer class for
/// AArch64.
/// \todo This should be generated by TableGen.
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64MACHINELEGALIZER_H
#define LLVM_LIB_TARGET_AARCH64_AARCH64MACHINELEGALIZER_H

#include "llvm/CodeGen/GlobalISel/Machinelegalizer.h"

namespace llvm {

class LLVMContext;

/// This class provides the information for the target register banks.
class AArch64MachineLegalizer : public MachineLegalizer {
public:
AArch64MachineLegalizer();
};
} // End llvm namespace.
#endif
5 changes: 5 additions & 0 deletions llvm/lib/Target/AArch64/AArch64Subtarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ const CallLowering *AArch64Subtarget::getCallLowering() const {
return GISel->getCallLowering();
}

const MachineLegalizer *AArch64Subtarget::getMachineLegalizer() const {
assert(GISel && "Access to GlobalISel APIs not set");
return GISel->getMachineLegalizer();
}

const RegisterBankInfo *AArch64Subtarget::getRegBankInfo() const {
assert(GISel && "Access to GlobalISel APIs not set");
return GISel->getRegBankInfo();
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/AArch64/AArch64Subtarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ class AArch64Subtarget : public AArch64GenSubtargetInfo {
return &getInstrInfo()->getRegisterInfo();
}
const CallLowering *getCallLowering() const override;
const MachineLegalizer *getMachineLegalizer() const override;
const RegisterBankInfo *getRegBankInfo() const override;
const Triple &getTargetTriple() const { return TargetTriple; }
bool enableMachineScheduler() const override { return true; }
Expand Down
12 changes: 12 additions & 0 deletions llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@

#include "AArch64.h"
#include "AArch64CallLowering.h"
#include "AArch64MachineLegalizer.h"
#include "AArch64RegisterBankInfo.h"
#include "AArch64TargetMachine.h"
#include "AArch64TargetObjectFile.h"
#include "AArch64TargetTransformInfo.h"
#include "llvm/CodeGen/GlobalISel/IRTranslator.h"
#include "llvm/CodeGen/GlobalISel/MachineLegalizePass.h"
#include "llvm/CodeGen/GlobalISel/RegBankSelect.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
Expand Down Expand Up @@ -196,10 +198,14 @@ AArch64TargetMachine::~AArch64TargetMachine() {}
namespace {
struct AArch64GISelActualAccessor : public GISelAccessor {
std::unique_ptr<CallLowering> CallLoweringInfo;
std::unique_ptr<MachineLegalizer> MachineLegalizer;
std::unique_ptr<RegisterBankInfo> RegBankInfo;
const CallLowering *getCallLowering() const override {
return CallLoweringInfo.get();
}
const class MachineLegalizer *getMachineLegalizer() const override {
return MachineLegalizer.get();
}
const RegisterBankInfo *getRegBankInfo() const override {
return RegBankInfo.get();
}
Expand Down Expand Up @@ -234,6 +240,7 @@ AArch64TargetMachine::getSubtargetImpl(const Function &F) const {
new AArch64GISelActualAccessor();
GISel->CallLoweringInfo.reset(
new AArch64CallLowering(*I->getTargetLowering()));
GISel->MachineLegalizer.reset(new AArch64MachineLegalizer());
GISel->RegBankInfo.reset(
new AArch64RegisterBankInfo(*I->getRegisterInfo()));
#endif
Expand Down Expand Up @@ -277,6 +284,7 @@ class AArch64PassConfig : public TargetPassConfig {
bool addInstSelector() override;
#ifdef LLVM_BUILD_GLOBAL_ISEL
bool addIRTranslator() override;
bool addLegalizeMachineIR() override;
bool addRegBankSelect() override;
#endif
bool addILPOpts() override;
Expand Down Expand Up @@ -375,6 +383,10 @@ bool AArch64PassConfig::addIRTranslator() {
addPass(new IRTranslator());
return false;
}
bool AArch64PassConfig::addLegalizeMachineIR() {
addPass(new MachineLegalizePass());
return false;
}
bool AArch64PassConfig::addRegBankSelect() {
addPass(new RegBankSelect());
return false;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/AArch64/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ add_public_tablegen_target(AArch64CommonTableGen)
# List of all GlobalISel files.
set(GLOBAL_ISEL_FILES
AArch64CallLowering.cpp
AArch64MachineLegalizer.cpp
AArch64RegisterBankInfo.cpp
)

Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ class GCNPassConfig final : public AMDGPUPassConfig {
bool addInstSelector() override;
#ifdef LLVM_BUILD_GLOBAL_ISEL
bool addIRTranslator() override;
bool addLegalizeMachineIR() override;
bool addRegBankSelect() override;
#endif
void addFastRegAlloc(FunctionPass *RegAllocPass) override;
Expand Down Expand Up @@ -520,6 +521,10 @@ bool GCNPassConfig::addIRTranslator() {
return false;
}

bool GCNPassConfig::addLegalizeMachineIR() {
return false;
}

bool GCNPassConfig::addRegBankSelect() {
return false;
}
Expand Down
34 changes: 34 additions & 0 deletions llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# RUN: llc -O0 -run-pass=legalize-mir -global-isel %s -o - 2>&1 | FileCheck %s
# REQUIRES: global-isel

--- |
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
target triple = "aarch64-apple-ios"
define void @test_vector_add() {
entry:
ret void
}
...

---
name: test_vector_add
isSSA: true
registers:
- { id: 0, class: _ }
- { id: 1, class: _ }
- { id: 2, class: _ }
body: |
bb.0.entry:
liveins: %q0, %q1, %q2, %q3
; CHECK-LABEL: name: test_vector_add
; CHECK-DAG: [[LHS_LO:%.*]](128), [[LHS_HI:%.*]](128) = G_EXTRACT <2 x s64> %0, 0, 128
; CHECK-DAG: [[RHS_LO:%.*]](128), [[RHS_HI:%.*]](128) = G_EXTRACT <2 x s64> %1, 0, 128
; CHECK: [[RES_LO:%.*]](128) = G_ADD <2 x s64> [[LHS_LO]], [[RHS_LO]]
; CHECK: [[RES_HI:%.*]](128) = G_ADD <2 x s64> [[LHS_HI]], [[RHS_HI]]
; CHECK: %2(256) = G_SEQUENCE <4 x s64> [[RES_LO]], [[RES_HI]]
%0(256) = G_SEQUENCE <4 x s64> %q0, %q1
%1(256) = G_SEQUENCE <4 x s64> %q2, %q3
%2(256) = G_ADD <4 x s64> %0, %1
%q0, %q1 = G_EXTRACT <2 x s64> %2, 0, 128
...