[llvm] r281205 - GlobalISel: translate GEP instructions.
Tim Northover via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 12 04:20:23 PDT 2016
Author: tnorthover
Date: Mon Sep 12 06:20:22 2016
New Revision: 281205
URL: http://llvm.org/viewvc/llvm-project?rev=281205&view=rev
Log:
GlobalISel: translate GEP instructions.
Unlike SDag, we use a separate G_GEP instruction (much simplified, only taking
a single byte offset) to preserve the pointer type information through
selection.
Added:
llvm/trunk/test/CodeGen/AArch64/GlobalISel/translate-gep.ll
Modified:
llvm/trunk/include/llvm/CodeGen/GlobalISel/IRTranslator.h
llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
llvm/trunk/include/llvm/Target/GenericOpcodes.td
llvm/trunk/include/llvm/Target/TargetOpcodes.def
llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp
llvm/trunk/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/IRTranslator.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/IRTranslator.h?rev=281205&r1=281204&r2=281205&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/IRTranslator.h (original)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/IRTranslator.h Mon Sep 12 06:20:22 2016
@@ -167,6 +167,8 @@ private:
bool translateSelect(const User &U);
+ bool translateGetElementPtr(const User &U);
+
/// Translate return (ret) instruction.
/// The target needs to implement CallLowering::lowerReturn for
/// this to succeed.
@@ -282,7 +284,6 @@ private:
bool translateCleanupRet(const User &U) { return false; }
bool translateCatchRet(const User &U) { return false; }
bool translateCatchSwitch(const User &U) { return false; }
- bool translateGetElementPtr(const User &U) { return false; }
bool translateFence(const User &U) { return false; }
bool translateAtomicCmpXchg(const User &U) { return false; }
bool translateAtomicRMW(const User &U) { return false; }
Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h?rev=281205&r1=281204&r2=281205&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h (original)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h Mon Sep 12 06:20:22 2016
@@ -161,6 +161,20 @@ public:
MachineInstrBuilder buildMul(unsigned Res, unsigned Op0,
unsigned Op1);
+ /// Build and insert \p Res<def> = G_GEP \p Op0, \p Op1
+ ///
+ /// G_GEP adds \p Op1 bytes to the pointer specified by \p Op0,
+ /// storing the resulting pointer in \p Res.
+ ///
+ /// \pre setBasicBlock or setMI must have been called.
+ /// \pre \p Res and \p Op0 must be generic virtual registers with pointer
+ /// type.
+ /// \pre \p Op1 must be a generic virtual register with scalar type.
+ ///
+ /// \return a MachineInstrBuilder for the newly created instruction.
+ MachineInstrBuilder buildGEP(unsigned Res, unsigned Op0,
+ unsigned Op1);
+
/// Build and insert \p Res<def>, \p CarryOut<def> = G_UADDE \p Op0,
/// \p Op1, \p CarryIn
///
@@ -221,6 +235,16 @@ public:
/// \return The newly created instruction.
MachineInstrBuilder buildZExt(unsigned Res, unsigned Op);
+ /// Build and insert \p Res<def> = G_SEXT \p Op, \p Res = G_TRUNC \p Op, or
+ /// \p Res = COPY \p Op depending on the differing sizes of \p Res and \p Op.
+ /// ///
+ /// \pre setBasicBlock or setMI must have been called.
+ /// \pre \p Res must be a generic virtual register with scalar or vector type.
+ /// \pre \p Op must be a generic virtual register with scalar or vector type.
+ ///
+ /// \return The newly created instruction.
+ MachineInstrBuilder buildSExtOrTrunc(unsigned Res, unsigned Op);
+
/// Build and insert G_BR \p Dest
///
/// G_BR is an unconditional branch to \p Dest.
Modified: llvm/trunk/include/llvm/Target/GenericOpcodes.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/GenericOpcodes.td?rev=281205&r1=281204&r2=281205&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Target/GenericOpcodes.td (original)
+++ llvm/trunk/include/llvm/Target/GenericOpcodes.td Mon Sep 12 06:20:22 2016
@@ -97,6 +97,13 @@ def G_ADD : Instruction {
let isCommutable = 1;
}
+// Generic pointer offset.
+def G_GEP : Instruction {
+ let OutOperandList = (outs type0:$dst);
+ let InOperandList = (ins type0:$src1, type1:$src2);
+ let hasSideEffects = 0;
+}
+
// Generic subtraction.
def G_SUB : Instruction {
let OutOperandList = (outs type0:$dst);
Modified: llvm/trunk/include/llvm/Target/TargetOpcodes.def
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetOpcodes.def?rev=281205&r1=281204&r2=281205&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Target/TargetOpcodes.def (original)
+++ llvm/trunk/include/llvm/Target/TargetOpcodes.def Mon Sep 12 06:20:22 2016
@@ -333,6 +333,9 @@ HANDLE_TARGET_OPCODE(G_SITOFP)
/// Generic unsigned-int to float conversion
HANDLE_TARGET_OPCODE(G_UITOFP)
+/// Generic unsigned-int to float conversion
+HANDLE_TARGET_OPCODE(G_GEP)
+
/// Generic BRANCH instruction. This is an unconditional branch.
HANDLE_TARGET_OPCODE(G_BR)
Modified: llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp?rev=281205&r1=281204&r2=281205&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp (original)
+++ llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp Mon Sep 12 06:20:22 2016
@@ -20,6 +20,7 @@
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
@@ -287,6 +288,77 @@ bool IRTranslator::translateCast(unsigne
return true;
}
+bool IRTranslator::translateGetElementPtr(const User &U) {
+ // FIXME: support vector GEPs.
+ if (U.getType()->isVectorTy())
+ return false;
+
+ Value &Op0 = *U.getOperand(0);
+ unsigned BaseReg = getOrCreateVReg(Op0);
+ LLT PtrTy(*Op0.getType());
+ unsigned PtrSize = DL->getPointerSizeInBits(PtrTy.getAddressSpace());
+ LLT OffsetTy = LLT::scalar(PtrSize);
+
+ int64_t Offset = 0;
+ for (gep_type_iterator GTI = gep_type_begin(&U), E = gep_type_end(&U);
+ GTI != E; ++GTI) {
+ const Value *Idx = GTI.getOperand();
+ if (StructType *StTy = dyn_cast<StructType>(*GTI)) {
+ unsigned Field = cast<Constant>(Idx)->getUniqueInteger().getZExtValue();
+ Offset += DL->getStructLayout(StTy)->getElementOffset(Field);
+ continue;
+ } else {
+ uint64_t ElementSize = DL->getTypeAllocSize(GTI.getIndexedType());
+
+ // If this is a scalar constant or a splat vector of constants,
+ // handle it quickly.
+ if (const auto *CI = dyn_cast<ConstantInt>(Idx)) {
+ Offset += ElementSize * CI->getSExtValue();
+ continue;
+ }
+
+ if (Offset != 0) {
+ unsigned NewBaseReg = MRI->createGenericVirtualRegister(PtrTy);
+ unsigned OffsetReg = MRI->createGenericVirtualRegister(OffsetTy);
+ MIRBuilder.buildConstant(OffsetReg, Offset);
+ MIRBuilder.buildGEP(NewBaseReg, BaseReg, OffsetReg);
+
+ BaseReg = NewBaseReg;
+ Offset = 0;
+ }
+
+ // N = N + Idx * ElementSize;
+ unsigned ElementSizeReg = MRI->createGenericVirtualRegister(OffsetTy);
+ MIRBuilder.buildConstant(ElementSizeReg, ElementSize);
+
+ unsigned IdxReg = getOrCreateVReg(*Idx);
+ if (MRI->getType(IdxReg) != OffsetTy) {
+ unsigned NewIdxReg = MRI->createGenericVirtualRegister(OffsetTy);
+ MIRBuilder.buildSExtOrTrunc(NewIdxReg, IdxReg);
+ IdxReg = NewIdxReg;
+ }
+
+ unsigned OffsetReg = MRI->createGenericVirtualRegister(OffsetTy);
+ MIRBuilder.buildMul(OffsetReg, ElementSizeReg, IdxReg);
+
+ unsigned NewBaseReg = MRI->createGenericVirtualRegister(PtrTy);
+ MIRBuilder.buildGEP(NewBaseReg, BaseReg, OffsetReg);
+ BaseReg = NewBaseReg;
+ }
+ }
+
+ if (Offset != 0) {
+ unsigned OffsetReg = MRI->createGenericVirtualRegister(OffsetTy);
+ MIRBuilder.buildConstant(OffsetReg, Offset);
+ MIRBuilder.buildGEP(getOrCreateVReg(U), BaseReg, OffsetReg);
+ return true;
+ }
+
+ MIRBuilder.buildCopy(getOrCreateVReg(U), BaseReg);
+ return true;
+}
+
+
bool IRTranslator::translateKnownIntrinsic(const CallInst &CI,
Intrinsic::ID ID) {
unsigned Op = 0;
Modified: llvm/trunk/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp?rev=281205&r1=281204&r2=281205&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp (original)
+++ llvm/trunk/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp Mon Sep 12 06:20:22 2016
@@ -97,6 +97,18 @@ MachineInstrBuilder MachineIRBuilder::bu
.addUse(Op1);
}
+MachineInstrBuilder MachineIRBuilder::buildGEP(unsigned Res, unsigned Op0,
+ unsigned Op1) {
+ assert(MRI->getType(Res).isPointer() &&
+ MRI->getType(Res) == MRI->getType(Op0) && "type mismatch");
+ assert(MRI->getType(Op1).isScalar() && "invalid offset type");
+
+ return buildInstr(TargetOpcode::G_GEP)
+ .addDef(Res)
+ .addUse(Op0)
+ .addUse(Op1);
+}
+
MachineInstrBuilder MachineIRBuilder::buildSub(unsigned Res, unsigned Op0,
unsigned Op1) {
assert((MRI->getType(Res).isScalar() || MRI->getType(Res).isVector()) &&
@@ -206,6 +218,17 @@ MachineInstrBuilder MachineIRBuilder::bu
return buildInstr(TargetOpcode::G_ZEXT).addDef(Res).addUse(Op);
}
+MachineInstrBuilder MachineIRBuilder::buildSExtOrTrunc(unsigned Res,
+ unsigned Op) {
+ unsigned Opcode = TargetOpcode::COPY;
+ if (MRI->getType(Res).getSizeInBits() > MRI->getType(Op).getSizeInBits())
+ Opcode = TargetOpcode::G_SEXT;
+ else if (MRI->getType(Res).getSizeInBits() < MRI->getType(Op).getSizeInBits())
+ Opcode = TargetOpcode::G_TRUNC;
+
+ return buildInstr(Opcode).addDef(Res).addUse(Op);
+}
+
MachineInstrBuilder MachineIRBuilder::buildExtract(ArrayRef<unsigned> Results,
ArrayRef<uint64_t> Indices,
unsigned Src) {
Added: llvm/trunk/test/CodeGen/AArch64/GlobalISel/translate-gep.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/GlobalISel/translate-gep.ll?rev=281205&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/GlobalISel/translate-gep.ll (added)
+++ llvm/trunk/test/CodeGen/AArch64/GlobalISel/translate-gep.ll Mon Sep 12 06:20:22 2016
@@ -0,0 +1,85 @@
+; RUN: llc -mtriple=aarch64-linux-gnu -O0 -global-isel -stop-after=irtranslator -o - %s | FileCheck %s
+
+%type = type [4 x {i8, i32}]
+
+define %type* @first_offset_const(%type* %addr) {
+; CHECK-LABEL: name: first_offset_const
+; CHECK: [[BASE:%[0-9]+]](p0) = COPY %x0
+; CHECK: [[OFFSET:%[0-9]+]](s64) = G_CONSTANT 32
+; CHECK: [[RES:%[0-9]+]](p0) = G_GEP [[BASE]], [[OFFSET]](s64)
+; CHECK: %x0 = COPY [[RES]](p0)
+
+ %res = getelementptr %type, %type* %addr, i32 1
+ ret %type* %res
+}
+
+define %type* @first_offset_trivial(%type* %addr) {
+; CHECK-LABEL: name: first_offset_trivial
+; CHECK: [[BASE:%[0-9]+]](p0) = COPY %x0
+; CHECK: [[TRIVIAL:%[0-9]+]](p0) = COPY [[BASE]](p0)
+; CHECK: %x0 = COPY [[TRIVIAL]](p0)
+
+ %res = getelementptr %type, %type* %addr, i32 0
+ ret %type* %res
+}
+
+define %type* @first_offset_variable(%type* %addr, i64 %idx) {
+; CHECK-LABEL: name: first_offset_variable
+; CHECK: [[BASE:%[0-9]+]](p0) = COPY %x0
+; CHECK: [[IDX:%[0-9]+]](s64) = COPY %x1
+; CHECK: [[SIZE:%[0-9]+]](s64) = G_CONSTANT 32
+; CHECK: [[OFFSET:%[0-9]+]](s64) = G_MUL [[SIZE]], [[IDX]]
+; CHECK: [[STEP0:%[0-9]+]](p0) = G_GEP [[BASE]], [[OFFSET]](s64)
+; CHECK: [[RES:%[0-9]+]](p0) = COPY [[STEP0]](p0)
+; CHECK: %x0 = COPY [[RES]](p0)
+
+ %res = getelementptr %type, %type* %addr, i64 %idx
+ ret %type* %res
+}
+
+define %type* @first_offset_ext(%type* %addr, i32 %idx) {
+; CHECK-LABEL: name: first_offset_ext
+; CHECK: [[BASE:%[0-9]+]](p0) = COPY %x0
+; CHECK: [[IDX32:%[0-9]+]](s32) = COPY %w1
+; CHECK: [[SIZE:%[0-9]+]](s64) = G_CONSTANT 32
+; CHECK: [[IDX64:%[0-9]+]](s64) = G_SEXT [[IDX32]](s32)
+; CHECK: [[OFFSET:%[0-9]+]](s64) = G_MUL [[SIZE]], [[IDX64]]
+; CHECK: [[STEP0:%[0-9]+]](p0) = G_GEP [[BASE]], [[OFFSET]](s64)
+; CHECK: [[RES:%[0-9]+]](p0) = COPY [[STEP0]](p0)
+; CHECK: %x0 = COPY [[RES]](p0)
+
+ %res = getelementptr %type, %type* %addr, i32 %idx
+ ret %type* %res
+}
+
+%type1 = type [4 x [4 x i32]]
+define i32* @const_then_var(%type1* %addr, i64 %idx) {
+; CHECK-LABEL: name: const_then_var
+; CHECK: [[BASE:%[0-9]+]](p0) = COPY %x0
+; CHECK: [[IDX:%[0-9]+]](s64) = COPY %x1
+; CHECK: [[OFFSET1:%[0-9]+]](s64) = G_CONSTANT 272
+; CHECK: [[BASE1:%[0-9]+]](p0) = G_GEP [[BASE]], [[OFFSET1]](s64)
+; CHECK: [[SIZE:%[0-9]+]](s64) = G_CONSTANT 4
+; CHECK: [[OFFSET2:%[0-9]+]](s64) = G_MUL [[SIZE]], [[IDX]]
+; CHECK: [[BASE2:%[0-9]+]](p0) = G_GEP [[BASE1]], [[OFFSET2]](s64)
+; CHECK: [[RES:%[0-9]+]](p0) = COPY [[BASE2]](p0)
+; CHECK: %x0 = COPY [[RES]](p0)
+
+ %res = getelementptr %type1, %type1* %addr, i32 4, i32 1, i64 %idx
+ ret i32* %res
+}
+
+define i32* @var_then_const(%type1* %addr, i64 %idx) {
+; CHECK-LABEL: name: var_then_const
+; CHECK: [[BASE:%[0-9]+]](p0) = COPY %x0
+; CHECK: [[IDX:%[0-9]+]](s64) = COPY %x1
+; CHECK: [[SIZE:%[0-9]+]](s64) = G_CONSTANT 64
+; CHECK: [[OFFSET1:%[0-9]+]](s64) = G_MUL [[SIZE]], [[IDX]]
+; CHECK: [[BASE1:%[0-9]+]](p0) = G_GEP [[BASE]], [[OFFSET1]](s64)
+; CHECK: [[OFFSET2:%[0-9]+]](s64) = G_CONSTANT 40
+; CHECK: [[BASE2:%[0-9]+]](p0) = G_GEP [[BASE1]], [[OFFSET2]](s64)
+; CHECK: %x0 = COPY [[BASE2]](p0)
+
+ %res = getelementptr %type1, %type1* %addr, i64 %idx, i32 2, i32 2
+ ret i32* %res
+}
More information about the llvm-commits
mailing list