Skip to content

Commit

Permalink
[PowerPC][GISel] add support for fpconstant
Browse files Browse the repository at this point in the history
Reviewed By: arsenm

Differential Revision: https://reviews.llvm.org/D133340
  • Loading branch information
chenzheng1030 committed Feb 14, 2023
1 parent 5561e17 commit 6ee2f77
Show file tree
Hide file tree
Showing 15 changed files with 263 additions and 1 deletion.
9 changes: 9 additions & 0 deletions llvm/docs/GlobalISel/GenericOpcode.rst
Expand Up @@ -69,6 +69,15 @@ The address of a basic block.
%0:_(p0) = G_BLOCK_ADDR blockaddress(@test_blockaddress, %ir-block.block)
G_CONSTANT_POOL
^^^^^^^^^^^^^^^

The address of an object in the constant pool.

.. code-block:: none
%0:_(p0) = G_CONSTANT_POOL %const.0
Integer Extension and Truncation
--------------------------------

Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
Expand Up @@ -359,6 +359,7 @@ class LegalizerHelper {
LegalizeResult bitcastInsertVectorElt(MachineInstr &MI, unsigned TypeIdx,
LLT CastTy);

LegalizeResult lowerFConstant(MachineInstr &MI);
LegalizeResult lowerBitcast(MachineInstr &MI);
LegalizeResult lowerLoad(GAnyLoad &MI);
LegalizeResult lowerStore(GStore &MI);
Expand Down
11 changes: 11 additions & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
Expand Up @@ -458,6 +458,17 @@ class MachineIRBuilder {
/// \return a MachineInstrBuilder for the newly created instruction.
MachineInstrBuilder buildGlobalValue(const DstOp &Res, const GlobalValue *GV);

/// Build and insert \p Res = G_CONSTANT_POOL \p Idx
///
/// G_CONSTANT_POOL materializes the address of an object in the constant
/// pool.
///
/// \pre setBasicBlock or setMI must have been called.
/// \pre \p Res must be a generic virtual register with pointer type.
///
/// \return a MachineInstrBuilder for the newly created instruction.
MachineInstrBuilder buildConstantPool(const DstOp &Res, unsigned Idx);

/// Build and insert \p Res = G_PTR_ADD \p Op0, \p Op1
///
/// G_PTR_ADD adds \p Op1 addressible units to the pointer specified by \p Op0,
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/Support/TargetOpcodes.def
Expand Up @@ -290,6 +290,10 @@ HANDLE_TARGET_OPCODE(G_FRAME_INDEX)
/// Generic reference to global value.
HANDLE_TARGET_OPCODE(G_GLOBAL_VALUE)

/// Generic instruction to materialize the address of an object in the constant
/// pool.
HANDLE_TARGET_OPCODE(G_CONSTANT_POOL)

/// Generic instruction to extract blocks of bits from the register given
/// (typically a sub-register COPY after instruction selection).
HANDLE_TARGET_OPCODE(G_EXTRACT)
Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/Target/GenericOpcodes.td
Expand Up @@ -106,6 +106,12 @@ def G_GLOBAL_VALUE : GenericInstruction {
let hasSideEffects = false;
}

def G_CONSTANT_POOL : GenericInstruction {
let OutOperandList = (outs type0:$dst);
let InOperandList = (ins unknown:$src);
let hasSideEffects = false;
}

def G_INTTOPTR : GenericInstruction {
let OutOperandList = (outs type0:$dst);
let InOperandList = (ins type1:$src);
Expand Down
29 changes: 29 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
Expand Up @@ -21,6 +21,7 @@
#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
Expand Down Expand Up @@ -2630,6 +2631,32 @@ static void getUnmergePieces(SmallVectorImpl<Register> &Pieces,
Pieces.push_back(Unmerge.getReg(I));
}

LegalizerHelper::LegalizeResult
LegalizerHelper::lowerFConstant(MachineInstr &MI) {
Register Dst = MI.getOperand(0).getReg();

MachineFunction &MF = MIRBuilder.getMF();
const DataLayout &DL = MIRBuilder.getDataLayout();

unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
LLT AddrPtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
Align Alignment = Align(DL.getABITypeAlign(
getFloatTypeForLLT(MF.getFunction().getContext(), MRI.getType(Dst))));

auto Addr = MIRBuilder.buildConstantPool(
AddrPtrTy, MF.getConstantPool()->getConstantPoolIndex(
MI.getOperand(1).getFPImm(), Alignment));

MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getConstantPool(MF), MachineMemOperand::MOLoad,
MRI.getType(Dst), Alignment);

MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, Dst, Addr, *MMO);
MI.eraseFromParent();

return Legalized;
}

LegalizerHelper::LegalizeResult
LegalizerHelper::lowerBitcast(MachineInstr &MI) {
Register Dst = MI.getOperand(0).getReg();
Expand Down Expand Up @@ -3250,6 +3277,8 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
switch(MI.getOpcode()) {
default:
return UnableToLegalize;
case TargetOpcode::G_FCONSTANT:
return lowerFConstant(MI);
case TargetOpcode::G_BITCAST:
return lowerBitcast(MI);
case TargetOpcode::G_SREM:
Expand Down
9 changes: 9 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
Expand Up @@ -164,6 +164,15 @@ MachineInstrBuilder MachineIRBuilder::buildGlobalValue(const DstOp &Res,
return MIB;
}

MachineInstrBuilder MachineIRBuilder::buildConstantPool(const DstOp &Res,
unsigned Idx) {
assert(Res.getLLTTy(*getMRI()).isPointer() && "invalid operand type");
auto MIB = buildInstr(TargetOpcode::G_CONSTANT_POOL);
Res.addDefToMIB(*getMRI(), MIB);
MIB.addConstantPoolIndex(Idx);
return MIB;
}

MachineInstrBuilder MachineIRBuilder::buildJumpTable(const LLT PtrTy,
unsigned JTI) {
return buildInstr(TargetOpcode::G_JUMP_TABLE, {PtrTy}, {})
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/CodeGen/MachineVerifier.cpp
Expand Up @@ -1746,6 +1746,13 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
report("alignment immediate must be >= 1", MI);
break;
}
case TargetOpcode::G_CONSTANT_POOL: {
if (!MI->getOperand(1).isCPI())
report("Src operand 1 must be a constant pool index", MI);
if (!MRI->getType(MI->getOperand(0).getReg()).isPointer())
report("Dst operand 0 must be a pointer", MI);
break;
}
default:
break;
}
Expand Down
69 changes: 68 additions & 1 deletion llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp
Expand Up @@ -12,6 +12,7 @@

#include "PPC.h"
#include "PPCInstrInfo.h"
#include "PPCMachineFunctionInfo.h"
#include "PPCRegisterBankInfo.h"
#include "PPCSubtarget.h"
#include "PPCTargetMachine.h"
Expand Down Expand Up @@ -54,6 +55,8 @@ class PPCInstructionSelector : public InstructionSelector {

bool selectZExt(MachineInstr &I, MachineBasicBlock &MBB,
MachineRegisterInfo &MRI) const;
bool selectConstantPool(MachineInstr &I, MachineBasicBlock &MBB,
MachineRegisterInfo &MRI) const;

std::optional<bool> selectI64ImmDirect(MachineInstr &I,
MachineBasicBlock &MBB,
Expand All @@ -62,6 +65,7 @@ class PPCInstructionSelector : public InstructionSelector {
bool selectI64Imm(MachineInstr &I, MachineBasicBlock &MBB,
MachineRegisterInfo &MRI) const;

const PPCTargetMachine &TM;
const PPCSubtarget &STI;
const PPCInstrInfo &TII;
const PPCRegisterInfo &TRI;
Expand All @@ -85,7 +89,8 @@ class PPCInstructionSelector : public InstructionSelector {
PPCInstructionSelector::PPCInstructionSelector(const PPCTargetMachine &TM,
const PPCSubtarget &STI,
const PPCRegisterBankInfo &RBI)
: STI(STI), TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()), RBI(RBI),
: TM(TM), STI(STI), TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()),
RBI(RBI),
#define GET_GLOBALISEL_PREDICATES_INIT
#include "PPCGenGlobalISel.inc"
#undef GET_GLOBALISEL_PREDICATES_INIT
Expand Down Expand Up @@ -636,6 +641,66 @@ bool PPCInstructionSelector::selectI64Imm(MachineInstr &I,
return true;
}

bool PPCInstructionSelector::selectConstantPool(
MachineInstr &I, MachineBasicBlock &MBB, MachineRegisterInfo &MRI) const {
const DebugLoc &DbgLoc = I.getDebugLoc();
MachineFunction *MF = MBB.getParent();

// TODO: handle 32-bit.
// TODO: Enabling floating point constant pool selection on AIX requires
// global isel on big endian target enabled first.
// See CallLowering::enableBigEndian().
if (!STI.isPPC64() || !STI.isLittleEndian())
return false;

MF->getInfo<PPCFunctionInfo>()->setUsesTOCBasePtr();

const Register DstReg = I.getOperand(0).getReg();
unsigned CPI = I.getOperand(1).getIndex();

// Address stored in the TOC entry. This is related to code model and the ABI
// we are currently using. For now we only handle 64-bit Linux LE. PowerPC
// only supports small, medium and large code model.
const CodeModel::Model CModel = TM.getCodeModel();
assert(!(CModel == CodeModel::Tiny || CModel == CodeModel::Kernel) &&
"PowerPC doesn't support tiny or kernel code models.");

const MCRegister TOCReg = STI.getTOCPointerRegister();
MachineMemOperand *MMO = MF->getMachineMemOperand(
MachinePointerInfo::getGOT(*MF), MachineMemOperand::MOLoad,
MRI.getType(DstReg), MF->getDataLayout().getPointerABIAlignment(0));

MachineInstr *MI = nullptr;
// For now we only handle 64-bit Linux.
if (CModel == CodeModel::Small) {
// For small code model, generate LDtocCPT(CPI, X2).
MI = BuildMI(MBB, I, DbgLoc, TII.get(PPC::LDtocCPT), DstReg)
.addConstantPoolIndex(CPI)
.addReg(TOCReg)
.addMemOperand(MMO);
} else {
Register HaAddrReg = MRI.createVirtualRegister(&PPC::G8RCRegClass);
BuildMI(MBB, I, DbgLoc, TII.get(PPC::ADDIStocHA8), HaAddrReg)
.addReg(TOCReg)
.addConstantPoolIndex(CPI);

if (CModel == CodeModel::Large)
// For large code model, generate LDtocL(CPI, ADDIStocHA8(X2, CPI))
MI = BuildMI(MBB, I, DbgLoc, TII.get(PPC::LDtocL), DstReg)
.addConstantPoolIndex(CPI)
.addReg(HaAddrReg)
.addMemOperand(MMO);
else
// For medium code model, generate ADDItocL(CPI, ADDIStocHA8(X2, CPI))
MI = BuildMI(MBB, I, DbgLoc, TII.get(PPC::ADDItocL), DstReg)
.addReg(HaAddrReg)
.addConstantPoolIndex(CPI);
}

I.eraseFromParent();
return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
}

bool PPCInstructionSelector::select(MachineInstr &I) {
auto &MBB = *I.getParent();
auto &MF = *MBB.getParent();
Expand Down Expand Up @@ -704,6 +769,8 @@ bool PPCInstructionSelector::select(MachineInstr &I) {
return selectZExt(I, MBB, MRI);
case TargetOpcode::G_CONSTANT:
return selectI64Imm(I, MBB, MRI);
case TargetOpcode::G_CONSTANT_POOL:
return selectConstantPool(I, MBB, MRI);
}
return false;
}
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp
Expand Up @@ -54,5 +54,8 @@ PPCLegalizerInfo::PPCLegalizerInfo(const PPCSubtarget &ST) {
getActionDefinitionsBuilder({G_LOAD, G_STORE})
.legalForTypesWithMemDesc({{S64, P0, S64, 8}, {S32, P0, S32, 4}});

getActionDefinitionsBuilder(G_FCONSTANT).lowerFor({S32, S64});
getActionDefinitionsBuilder(G_CONSTANT_POOL).legalFor({P0});

getLegacyLegalizerInfo().computeTables();
}
3 changes: 3 additions & 0 deletions llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp
Expand Up @@ -118,6 +118,9 @@ PPCRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case TargetOpcode::G_CONSTANT:
OperandsMapping = getOperandsMapping({getValueMapping(PMI_GPR64), nullptr});
break;
case TargetOpcode::G_CONSTANT_POOL:
OperandsMapping = getOperandsMapping({getValueMapping(PMI_GPR64), nullptr});
break;
case TargetOpcode::G_FPTOUI:
case TargetOpcode::G_FPTOSI: {
Register SrcReg = MI.getOperand(1).getReg();
Expand Down
Expand Up @@ -86,6 +86,10 @@
# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
#
# DEBUG-NEXT: G_CONSTANT_POOL (opcode {{[0-9]+}}): 1 type index, 0 imm indices
# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
#
# DEBUG-NEXT: G_EXTRACT (opcode {{[0-9]+}}): 2 type indices, 1 imm index
# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
Expand Down
13 changes: 13 additions & 0 deletions llvm/test/CodeGen/PowerPC/GlobalISel/fconstant-unsupported.ll
@@ -0,0 +1,13 @@
; RUN: not --crash llc -global-isel -mtriple=powerpc-unknown-linux-gnu \
; RUN: -o - < %s 2>&1 | FileCheck %s --check-prefix=BE
; RUN: not --crash llc -global-isel -mtriple=powerpcle-unknown-linux-gnu \
; RUN: -o - < %s 2>&1 | FileCheck %s --check-prefix=BIT32

; BE: LLVM ERROR: unable to translate in big endian mode

; BIT32: LLVM ERROR: unable to legalize instruction: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD{{.*}}load (s64) from constant-pool

define double @foo() {
entry:
ret double 1.000000e+00
}
56 changes: 56 additions & 0 deletions llvm/test/CodeGen/PowerPC/GlobalISel/fconstant.ll
@@ -0,0 +1,56 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py

; RUN: llc -mtriple=powerpc64le-unknown-linux-gnu -global-isel -code-model=small \
; RUN: -verify-machineinstrs -o - < %s | FileCheck %s --check-prefix=SMALL
; RUN: llc -mtriple=powerpc64le-unknown-linux-gnu -global-isel -code-model=medium \
; RUN: -verify-machineinstrs -o - < %s | FileCheck %s --check-prefix=MEDIUM
; RUN: llc -mtriple=powerpc64le-unknown-linux-gnu -global-isel -code-model=large \
; RUN: -verify-machineinstrs -o - < %s | FileCheck %s --check-prefix=LARGE

define float @foo_float() {
; SMALL-LABEL: foo_float:
; SMALL: # %bb.0: # %entry
; SMALL-NEXT: ld 3, .LC0@toc(2)
; SMALL-NEXT: lfs 1, 0(3)
; SMALL-NEXT: blr
;
; MEDIUM-LABEL: foo_float:
; MEDIUM: # %bb.0: # %entry
; MEDIUM-NEXT: addis 3, 2, .LCPI0_0@toc@ha
; MEDIUM-NEXT: addi 3, 3, .LCPI0_0@toc@l
; MEDIUM-NEXT: lfs 1, 0(3)
; MEDIUM-NEXT: blr
;
; LARGE-LABEL: foo_float:
; LARGE: # %bb.0: # %entry
; LARGE-NEXT: addis 3, 2, .LC0@toc@ha
; LARGE-NEXT: ld 3, .LC0@toc@l(3)
; LARGE-NEXT: lfs 1, 0(3)
; LARGE-NEXT: blr
entry:
ret float 1.000000e+00
}

define double @foo_double() {
; SMALL-LABEL: foo_double:
; SMALL: # %bb.0: # %entry
; SMALL-NEXT: ld 3, .LC1@toc(2)
; SMALL-NEXT: lfd 1, 0(3)
; SMALL-NEXT: blr
;
; MEDIUM-LABEL: foo_double:
; MEDIUM: # %bb.0: # %entry
; MEDIUM-NEXT: addis 3, 2, .LCPI1_0@toc@ha
; MEDIUM-NEXT: addi 3, 3, .LCPI1_0@toc@l
; MEDIUM-NEXT: lfd 1, 0(3)
; MEDIUM-NEXT: blr
;
; LARGE-LABEL: foo_double:
; LARGE: # %bb.0: # %entry
; LARGE-NEXT: addis 3, 2, .LC1@toc@ha
; LARGE-NEXT: ld 3, .LC1@toc@l(3)
; LARGE-NEXT: lfd 1, 0(3)
; LARGE-NEXT: blr
entry:
ret double 1.000000e+00
}
40 changes: 40 additions & 0 deletions llvm/test/MachineVerifier/test_g_constant_pool.mir
@@ -0,0 +1,40 @@
# RUN: not --crash llc -o - -march=arm64 -global-isel -run-pass=none \
# RUN: -verify-machineinstrs %s 2>&1 | FileCheck %s
# REQUIRES: aarch64-registered-target

---
name: test_constant_pool
constants:
- id: 0
value: 'double 3.250000e+00'
stack:
- { id: 0, size: 64, alignment: 8 }
legalized: true
regBankSelected: false
selected: false
tracksRegLiveness: true
liveins:
body: |
bb.0:
; CHECK: Bad machine code: Too few operands
%0:_(p0) = G_CONSTANT_POOL
; CHECK: Bad machine code: Src operand 1 must be a constant pool index
%1:_(p0) = G_CONSTANT_POOL 1
; CHECK: Bad machine code: Src operand 1 must be a constant pool index
%2:_(p0) = G_CONSTANT_POOL i32 1
; CHECK: Bad machine code: Src operand 1 must be a constant pool index
%3:_(p0) = G_CONSTANT_POOL %stack.0
; CHECK: Dst operand 0 must be a pointer
%4:_(s32) = G_CONSTANT_POOL %const.0
; CHECK: Dst operand 0 must be a pointer
%5:_(s64) = G_CONSTANT_POOL %const.0
; CHECK-NOT: %6
%6:_(p0) = G_CONSTANT_POOL %const.0
...

0 comments on commit 6ee2f77

Please sign in to comment.