forked from OSchip/llvm-project
GlobalISel: translate dynamic alloca instructions.
llvm-svn: 294022
This commit is contained in:
parent
6de201ec32
commit
c3e3f59d12
|
@ -155,11 +155,6 @@ private:
|
|||
bool translateCast(unsigned Opcode, const User &U,
|
||||
MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate static alloca instruction (i.e. one of constant size and in the
|
||||
/// first basic block).
|
||||
bool translateStaticAlloca(const AllocaInst &Inst,
|
||||
MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate a phi instruction.
|
||||
bool translatePHI(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
|
@ -202,6 +197,8 @@ private:
|
|||
|
||||
bool translateGetElementPtr(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateAlloca(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate return (ret) instruction.
|
||||
/// The target needs to implement CallLowering::lowerReturn for
|
||||
/// this to succeed.
|
||||
|
@ -239,9 +236,6 @@ private:
|
|||
bool translateSRem(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_SREM, U, MIRBuilder);
|
||||
}
|
||||
bool translateAlloca(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateStaticAlloca(cast<AllocaInst>(U), MIRBuilder);
|
||||
}
|
||||
bool translateIntToPtr(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateCast(TargetOpcode::G_INTTOPTR, U, MIRBuilder);
|
||||
}
|
||||
|
|
|
@ -246,6 +246,19 @@ public:
|
|||
MachineInstrBuilder buildUAdde(unsigned Res, unsigned CarryOut, unsigned Op0,
|
||||
unsigned Op1, unsigned CarryIn);
|
||||
|
||||
/// Build and insert \p Res<def> = G_AND \p Op0, \p Op1
|
||||
///
|
||||
/// G_AND sets \p Res to the bitwise and of integer parameters \p Op0 and \p
|
||||
/// Op1.
|
||||
///
|
||||
/// \pre setBasicBlock or setMI must have been called.
|
||||
/// \pre \p Res, \p Op0 and \p Op1 must be generic virtual registers
|
||||
/// with the same (scalar or vector) type).
|
||||
///
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildAnd(unsigned Res, unsigned Op0,
|
||||
unsigned Op1);
|
||||
|
||||
/// Build and insert \p Res<def> = G_ANYEXT \p Op0
|
||||
///
|
||||
/// G_ANYEXT produces a register of the specified width, with bits 0 to
|
||||
|
@ -299,6 +312,16 @@ public:
|
|||
/// \return The newly created instruction.
|
||||
MachineInstrBuilder buildSExtOrTrunc(unsigned Res, unsigned Op);
|
||||
|
||||
/// Build and insert \p Res<def> = G_ZEXT \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 buildZExtOrTrunc(unsigned Res, unsigned Op);
|
||||
|
||||
/// Build and insert G_BR \p Dest
|
||||
///
|
||||
/// G_BR is an unconditional branch to \p Dest.
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "llvm/IR/IntrinsicInst.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/Target/TargetFrameLowering.h"
|
||||
#include "llvm/Target/TargetIntrinsicInfo.h"
|
||||
#include "llvm/Target/TargetLowering.h"
|
||||
|
||||
|
@ -820,15 +821,81 @@ bool IRTranslator::translateLandingPad(const User &U,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool IRTranslator::translateStaticAlloca(const AllocaInst &AI,
|
||||
MachineIRBuilder &MIRBuilder) {
|
||||
if (!TPC->isGlobalISelAbortEnabled() && !AI.isStaticAlloca())
|
||||
return false;
|
||||
bool IRTranslator::translateAlloca(const User &U,
|
||||
MachineIRBuilder &MIRBuilder) {
|
||||
auto &AI = cast<AllocaInst>(U);
|
||||
|
||||
assert(AI.isStaticAlloca() && "only handle static allocas now");
|
||||
unsigned Res = getOrCreateVReg(AI);
|
||||
int FI = getOrCreateFrameIndex(AI);
|
||||
MIRBuilder.buildFrameIndex(Res, FI);
|
||||
if (AI.isStaticAlloca()) {
|
||||
unsigned Res = getOrCreateVReg(AI);
|
||||
int FI = getOrCreateFrameIndex(AI);
|
||||
MIRBuilder.buildFrameIndex(Res, FI);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Now we're in the harder dynamic case.
|
||||
Type *Ty = AI.getAllocatedType();
|
||||
unsigned Align =
|
||||
std::max((unsigned)DL->getPrefTypeAlignment(Ty), AI.getAlignment());
|
||||
|
||||
unsigned NumElts = getOrCreateVReg(*AI.getArraySize());
|
||||
|
||||
LLT IntPtrTy = LLT::scalar(DL->getPointerSizeInBits());
|
||||
if (MRI->getType(NumElts) != IntPtrTy) {
|
||||
unsigned ExtElts = MRI->createGenericVirtualRegister(IntPtrTy);
|
||||
MIRBuilder.buildZExtOrTrunc(ExtElts, NumElts);
|
||||
NumElts = ExtElts;
|
||||
}
|
||||
|
||||
unsigned AllocSize = MRI->createGenericVirtualRegister(IntPtrTy);
|
||||
unsigned TySize = MRI->createGenericVirtualRegister(IntPtrTy);
|
||||
MIRBuilder.buildConstant(TySize, DL->getTypeAllocSize(Ty));
|
||||
MIRBuilder.buildMul(AllocSize, NumElts, TySize);
|
||||
|
||||
LLT PtrTy = LLT{*AI.getType(), *DL};
|
||||
auto &TLI = *MF->getSubtarget().getTargetLowering();
|
||||
unsigned SPReg = TLI.getStackPointerRegisterToSaveRestore();
|
||||
|
||||
unsigned SPTmp = MRI->createGenericVirtualRegister(PtrTy);
|
||||
MIRBuilder.buildCopy(SPTmp, SPReg);
|
||||
|
||||
unsigned SPInt = MRI->createGenericVirtualRegister(IntPtrTy);
|
||||
MIRBuilder.buildInstr(TargetOpcode::G_PTRTOINT).addDef(SPInt).addUse(SPTmp);
|
||||
|
||||
unsigned AllocInt = MRI->createGenericVirtualRegister(IntPtrTy);
|
||||
MIRBuilder.buildSub(AllocInt, SPInt, AllocSize);
|
||||
|
||||
// Handle alignment. We have to realign if the allocation granule was smaller
|
||||
// than stack alignment, or the specific alloca requires more than stack
|
||||
// alignment.
|
||||
unsigned StackAlign =
|
||||
MF->getSubtarget().getFrameLowering()->getStackAlignment();
|
||||
Align = std::max(Align, StackAlign);
|
||||
if (Align > StackAlign || DL->getTypeAllocSize(Ty) % StackAlign != 0) {
|
||||
// Round the size of the allocation up to the stack alignment size
|
||||
// by add SA-1 to the size. This doesn't overflow because we're computing
|
||||
// an address inside an alloca.
|
||||
unsigned TmpSize = MRI->createGenericVirtualRegister(IntPtrTy);
|
||||
unsigned AlignMinus1 = MRI->createGenericVirtualRegister(IntPtrTy);
|
||||
MIRBuilder.buildConstant(AlignMinus1, Align - 1);
|
||||
MIRBuilder.buildSub(TmpSize, AllocInt, AlignMinus1);
|
||||
|
||||
unsigned AlignedAlloc = MRI->createGenericVirtualRegister(IntPtrTy);
|
||||
unsigned AlignMask = MRI->createGenericVirtualRegister(IntPtrTy);
|
||||
MIRBuilder.buildConstant(AlignMask, -(uint64_t)Align);
|
||||
MIRBuilder.buildAnd(AlignedAlloc, TmpSize, AlignMask);
|
||||
|
||||
AllocInt = AlignedAlloc;
|
||||
}
|
||||
|
||||
unsigned DstReg = getOrCreateVReg(AI);
|
||||
MIRBuilder.buildInstr(TargetOpcode::G_INTTOPTR)
|
||||
.addDef(DstReg)
|
||||
.addUse(AllocInt);
|
||||
|
||||
MIRBuilder.buildCopy(SPReg, DstReg);
|
||||
|
||||
MF->getFrameInfo().CreateVariableSizedObject(Align ? Align : 1, &AI);
|
||||
assert(MF->getFrameInfo().hasVarSizedObjects());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -213,6 +213,19 @@ MachineInstrBuilder MachineIRBuilder::buildMul(unsigned Res, unsigned Op0,
|
|||
.addUse(Op1);
|
||||
}
|
||||
|
||||
MachineInstrBuilder MachineIRBuilder::buildAnd(unsigned Res, unsigned Op0,
|
||||
unsigned Op1) {
|
||||
assert((MRI->getType(Res).isScalar() || MRI->getType(Res).isVector()) &&
|
||||
"invalid operand type");
|
||||
assert(MRI->getType(Res) == MRI->getType(Op0) &&
|
||||
MRI->getType(Res) == MRI->getType(Op1) && "type mismatch");
|
||||
|
||||
return buildInstr(TargetOpcode::G_AND)
|
||||
.addDef(Res)
|
||||
.addUse(Op0)
|
||||
.addUse(Op1);
|
||||
}
|
||||
|
||||
MachineInstrBuilder MachineIRBuilder::buildBr(MachineBasicBlock &Dest) {
|
||||
return buildInstr(TargetOpcode::G_BR).addMBB(&Dest);
|
||||
}
|
||||
|
@ -327,6 +340,17 @@ MachineInstrBuilder MachineIRBuilder::buildSExtOrTrunc(unsigned Res,
|
|||
return buildInstr(Opcode).addDef(Res).addUse(Op);
|
||||
}
|
||||
|
||||
MachineInstrBuilder MachineIRBuilder::buildZExtOrTrunc(unsigned Res,
|
||||
unsigned Op) {
|
||||
unsigned Opcode = TargetOpcode::COPY;
|
||||
if (MRI->getType(Res).getSizeInBits() > MRI->getType(Op).getSizeInBits())
|
||||
Opcode = TargetOpcode::G_ZEXT;
|
||||
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) {
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
; RUN: llc -mtriple=aarch64 -global-isel %s -o - -stop-after=irtranslator | FileCheck %s
|
||||
|
||||
; CHECK-LABEL: name: test_simple_alloca
|
||||
; CHECK: [[NUMELTS:%[0-9]+]](s32) = COPY %w0
|
||||
; CHECK: [[NUMELTS_64:%[0-9]+]](s64) = G_ZEXT [[NUMELTS]](s32)
|
||||
; CHECK: [[TYPE_SIZE:%[0-9]+]](s64) = G_CONSTANT i64 1
|
||||
; CHECK: [[NUMBYTES:%[0-9]+]](s64) = G_MUL [[NUMELTS_64]], [[TYPE_SIZE]]
|
||||
; CHECK: [[SP_TMP:%[0-9]+]](p0) = COPY %sp
|
||||
; CHECK: [[SP_INT:%[0-9]+]](s64) = G_PTRTOINT [[SP_TMP]](p0)
|
||||
; CHECK: [[ALLOC:%[0-9]+]](s64) = G_SUB [[SP_INT]], [[NUMBYTES]]
|
||||
; CHECK: [[ALIGN_M_1:%[0-9]+]](s64) = G_CONSTANT i64 15
|
||||
; CHECK: [[ALIGN_TMP:%[0-9]+]](s64) = G_SUB [[ALLOC]], [[ALIGN_M_1]]
|
||||
; CHECK: [[ALIGN_MASK:%[0-9]+]](s64) = G_CONSTANT i64 -16
|
||||
; CHECK: [[ALIGNED_ALLOC:%[0-9]+]](s64) = G_AND [[ALIGN_TMP]], [[ALIGN_MASK]]
|
||||
; CHECK: [[ALLOC_PTR:%[0-9]+]](p0) = G_INTTOPTR [[ALIGNED_ALLOC]](s64)
|
||||
; CHECK: %sp = COPY [[ALLOC_PTR]]
|
||||
; CHECK: %x0 = COPY [[ALLOC_PTR]]
|
||||
define i8* @test_simple_alloca(i32 %numelts) {
|
||||
%addr = alloca i8, i32 %numelts
|
||||
ret i8* %addr
|
||||
}
|
||||
|
||||
; CHECK-LABEL: name: test_aligned_alloca
|
||||
; CHECK: [[NUMELTS:%[0-9]+]](s32) = COPY %w0
|
||||
; CHECK: [[NUMELTS_64:%[0-9]+]](s64) = G_ZEXT [[NUMELTS]](s32)
|
||||
; CHECK: [[TYPE_SIZE:%[0-9]+]](s64) = G_CONSTANT i64 1
|
||||
; CHECK: [[NUMBYTES:%[0-9]+]](s64) = G_MUL [[NUMELTS_64]], [[TYPE_SIZE]]
|
||||
; CHECK: [[SP_TMP:%[0-9]+]](p0) = COPY %sp
|
||||
; CHECK: [[SP_INT:%[0-9]+]](s64) = G_PTRTOINT [[SP_TMP]](p0)
|
||||
; CHECK: [[ALLOC:%[0-9]+]](s64) = G_SUB [[SP_INT]], [[NUMBYTES]]
|
||||
; CHECK: [[ALIGN_M_1:%[0-9]+]](s64) = G_CONSTANT i64 31
|
||||
; CHECK: [[ALIGN_TMP:%[0-9]+]](s64) = G_SUB [[ALLOC]], [[ALIGN_M_1]]
|
||||
; CHECK: [[ALIGN_MASK:%[0-9]+]](s64) = G_CONSTANT i64 -32
|
||||
; CHECK: [[ALIGNED_ALLOC:%[0-9]+]](s64) = G_AND [[ALIGN_TMP]], [[ALIGN_MASK]]
|
||||
; CHECK: [[ALLOC_PTR:%[0-9]+]](p0) = G_INTTOPTR [[ALIGNED_ALLOC]](s64)
|
||||
; CHECK: %sp = COPY [[ALLOC_PTR]]
|
||||
; CHECK: %x0 = COPY [[ALLOC_PTR]]
|
||||
define i8* @test_aligned_alloca(i32 %numelts) {
|
||||
%addr = alloca i8, i32 %numelts, align 32
|
||||
ret i8* %addr
|
||||
}
|
||||
|
||||
; CHECK-LABEL: name: test_natural_alloca
|
||||
; CHECK: [[NUMELTS:%[0-9]+]](s32) = COPY %w0
|
||||
; CHECK: [[NUMELTS_64:%[0-9]+]](s64) = G_ZEXT [[NUMELTS]](s32)
|
||||
; CHECK: [[TYPE_SIZE:%[0-9]+]](s64) = G_CONSTANT i64 16
|
||||
; CHECK: [[NUMBYTES:%[0-9]+]](s64) = G_MUL [[NUMELTS_64]], [[TYPE_SIZE]]
|
||||
; CHECK: [[SP_TMP:%[0-9]+]](p0) = COPY %sp
|
||||
; CHECK: [[SP_INT:%[0-9]+]](s64) = G_PTRTOINT [[SP_TMP]](p0)
|
||||
; CHECK: [[ALLOC:%[0-9]+]](s64) = G_SUB [[SP_INT]], [[NUMBYTES]]
|
||||
; CHECK: [[ALLOC_PTR:%[0-9]+]](p0) = G_INTTOPTR [[ALLOC]](s64)
|
||||
; CHECK: %sp = COPY [[ALLOC_PTR]]
|
||||
; CHECK: %x0 = COPY [[ALLOC_PTR]]
|
||||
define i128* @test_natural_alloca(i32 %numelts) {
|
||||
%addr = alloca i128, i32 %numelts
|
||||
ret i128* %addr
|
||||
}
|
Loading…
Reference in New Issue