From: Tim Northover Date: Fri, 3 Feb 2017 18:22:45 +0000 (+0000) Subject: GlobalISel: translate dynamic alloca instructions. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=30af5932fd43a53158bfa1cb6a3e4b1630d8064c;p=llvm GlobalISel: translate dynamic alloca instructions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@294022 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/include/llvm/CodeGen/GlobalISel/IRTranslator.h index 25e8588c437..352eebd58c5 100644 --- a/include/llvm/CodeGen/GlobalISel/IRTranslator.h +++ b/include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -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(U), MIRBuilder); - } bool translateIntToPtr(const User &U, MachineIRBuilder &MIRBuilder) { return translateCast(TargetOpcode::G_INTTOPTR, U, MIRBuilder); } diff --git a/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h index 353aab5e12b..008494efb38 100644 --- a/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -246,6 +246,19 @@ public: MachineInstrBuilder buildUAdde(unsigned Res, unsigned CarryOut, unsigned Op0, unsigned Op1, unsigned CarryIn); + /// Build and insert \p Res = 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 = 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 = 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. diff --git a/lib/CodeGen/GlobalISel/IRTranslator.cpp b/lib/CodeGen/GlobalISel/IRTranslator.cpp index d8dc6a37a52..a1a1d7b9fb5 100644 --- a/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -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(U); + + 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); - assert(AI.isStaticAlloca() && "only handle static allocas now"); - unsigned Res = getOrCreateVReg(AI); - int FI = getOrCreateFrameIndex(AI); - MIRBuilder.buildFrameIndex(Res, FI); + MF->getFrameInfo().CreateVariableSizedObject(Align ? Align : 1, &AI); + assert(MF->getFrameInfo().hasVarSizedObjects()); return true; } diff --git a/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp index 01457260ca6..665fb7057df 100644 --- a/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -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 Results, ArrayRef Indices, unsigned Src) { diff --git a/test/CodeGen/AArch64/GlobalISel/dynamic-alloca.ll b/test/CodeGen/AArch64/GlobalISel/dynamic-alloca.ll new file mode 100644 index 00000000000..df608b61b3a --- /dev/null +++ b/test/CodeGen/AArch64/GlobalISel/dynamic-alloca.ll @@ -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 +}