From: Tim Northover Date: Fri, 22 Jul 2016 16:59:52 +0000 (+0000) Subject: GlobalISel: implement alloca instruction X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bd5054602ebad1d9d1a0753980c69ae6e08a168e;p=platform%2Fupstream%2Fllvm.git GlobalISel: implement alloca instruction llvm-svn: 276433 --- diff --git a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h index 833e874..b61f5bb 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -93,6 +93,10 @@ private: /// \return true if the translation succeeded. bool translate(const Instruction &Inst); + /// Translate alloca instruction (i.e. one of constant size and in the first + /// basic block). + bool translateStaticAlloca(const AllocaInst &Inst); + /// Translate \p Inst into a binary operation \p Opcode. /// \pre \p Inst is a binary operation. bool translateBinaryOp(unsigned Opcode, const Instruction &Inst); @@ -117,6 +121,8 @@ private: /// MachineRegisterInfo used to create virtual registers. MachineRegisterInfo *MRI; + const DataLayout *DL; + // * Insert all the code needed to materialize the constants // at the proper place. E.g., Entry block or dominator block // of each constant depending on how fancy we want to be. diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h index 4c2ebd1..6728f4f 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -141,6 +141,17 @@ public: /// /// \return The newly created instruction. MachineInstr *buildInstr(unsigned Opcode); + + /// Build and insert \p Res = G_FRAME_INDEX \p Ty \p Idx + /// + /// G_FRAME_INDEX materializes the address of an alloca value or other + /// stack-based object. + /// + /// \pre setBasicBlock or setMI must have been called. + /// + /// \return The newly created instruction. + MachineInstr *buildFrameIndex(LLT Ty, unsigned Res, int Idx); + }; } // End namespace llvm. diff --git a/llvm/include/llvm/CodeGen/LowLevelType.h b/llvm/include/llvm/CodeGen/LowLevelType.h index 0c809a7..d2fde62 100644 --- a/llvm/include/llvm/CodeGen/LowLevelType.h +++ b/llvm/include/llvm/CodeGen/LowLevelType.h @@ -42,6 +42,7 @@ public: enum TypeKind : uint16_t { Invalid, Scalar, + Pointer, Vector, Unsized, }; @@ -51,6 +52,12 @@ public: return LLT{Scalar, 1, SizeInBits}; } + /// \brief get a low-level pointer in the given address space (defaulting to + /// 0). + static LLT pointer(unsigned AddressSpace) { + return LLT{Pointer, 1, AddressSpace}; + } + /// \brief get a low-level vector of some number of elements and element /// width. \p NumElements must be at least 2. static LLT vector(uint16_t NumElements, unsigned ScalarSizeInBits) { @@ -72,13 +79,13 @@ public: return LLT{Unsized, 1, 0}; } - explicit LLT(TypeKind Kind, uint16_t NumElements, unsigned ScalarSizeInBits) - : ScalarSize(ScalarSizeInBits), NumElements(NumElements), Kind(Kind) { + explicit LLT(TypeKind Kind, uint16_t NumElements, unsigned SizeOrAddrSpace) + : SizeOrAddrSpace(SizeOrAddrSpace), NumElements(NumElements), Kind(Kind) { assert((Kind != Vector || NumElements > 1) && "invalid number of vector elements"); } - explicit LLT() : ScalarSize(0), NumElements(0), Kind(Invalid) {} + explicit LLT() : SizeOrAddrSpace(0), NumElements(0), Kind(Invalid) {} /// \brief construct a low-level type based on an LLVM type. explicit LLT(const Type &Ty); @@ -87,6 +94,8 @@ public: bool isScalar() const { return Kind == Scalar; } + bool isPointer() const { return Kind == Pointer; } + bool isVector() const { return Kind == Vector; } bool isSized() const { return Kind == Scalar || Kind == Vector; } @@ -102,18 +111,23 @@ public: /// types. unsigned getSizeInBits() const { assert(isSized() && "attempt to get size of unsized type"); - return ScalarSize * NumElements; + return SizeOrAddrSpace * NumElements; } unsigned getScalarSizeInBits() const { assert(isSized() && "cannot get size of this type"); - return ScalarSize; + return SizeOrAddrSpace; + } + + unsigned getAddressSpace() const { + assert(isPointer() && "cannot get address space of non-pointer type"); + return SizeOrAddrSpace; } /// \brief Returns the vector's element type. Only valid for vector types. LLT getElementType() const { assert(isVector() && "cannot get element type of scalar/aggregate"); - return scalar(ScalarSize); + return scalar(SizeOrAddrSpace); } /// \brief get a low-level type with half the size of the original, by halving @@ -121,7 +135,7 @@ public: /// `s16`, `<2 x s32>` will become `<2 x s16>`. LLT halfScalarSize() const { assert(isSized() && "cannot change size of this type"); - return LLT{Kind, NumElements, ScalarSize / 2}; + return LLT{Kind, NumElements, SizeOrAddrSpace / 2}; } /// \brief get a low-level type with twice the size of the original, by @@ -129,7 +143,7 @@ public: /// become `s64`, `<2 x s32>` will become `<2 x s64>`. LLT doubleScalarSize() const { assert(isSized() && "cannot change size of this type"); - return LLT{Kind, NumElements, ScalarSize * 2}; + return LLT{Kind, NumElements, SizeOrAddrSpace * 2}; } /// \brief get a low-level type with half the size of the original, by halving @@ -139,9 +153,9 @@ public: LLT halfElements() const { assert(isVector() && NumElements % 2 == 0 && "cannot half odd vector"); if (NumElements == 2) - return scalar(ScalarSize); + return scalar(SizeOrAddrSpace); - return LLT{Vector, static_cast(NumElements / 2), ScalarSize}; + return LLT{Vector, static_cast(NumElements / 2), SizeOrAddrSpace}; } /// \brief get a low-level type with twice the size of the original, by @@ -149,19 +163,19 @@ public: /// source must be a vector type. For example `<2 x s32>` will become `<4 x /// s32>`. Doubling the number of elements in sN produces <2 x sN>. LLT doubleElements() const { - return LLT{Vector, static_cast(NumElements * 2), ScalarSize}; + return LLT{Vector, static_cast(NumElements * 2), SizeOrAddrSpace}; } void print(raw_ostream &OS) const; bool operator ==(const LLT &RHS) const { - return Kind == RHS.Kind && ScalarSize == RHS.ScalarSize && + return Kind == RHS.Kind && SizeOrAddrSpace == RHS.SizeOrAddrSpace && NumElements == RHS.NumElements; } friend struct DenseMapInfo; private: - unsigned ScalarSize; + unsigned SizeOrAddrSpace; uint16_t NumElements; TypeKind Kind; }; @@ -174,7 +188,7 @@ template<> struct DenseMapInfo { return LLT{LLT::Invalid, 0, -2u}; } static inline unsigned getHashValue(const LLT &Ty) { - uint64_t Val = ((uint64_t)Ty.ScalarSize << 32) | + uint64_t Val = ((uint64_t)Ty.SizeOrAddrSpace << 32) | ((uint64_t)Ty.NumElements << 16) | (uint64_t)Ty.Kind; return DenseMapInfo::getHashValue(Val); } diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td index 889523e..9703635 100644 --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -13,6 +13,16 @@ //===----------------------------------------------------------------------===// //------------------------------------------------------------------------------ +// Unary ops. +//------------------------------------------------------------------------------ + +def G_FRAME_INDEX : Instruction { + let OutOperandList = (outs unknown:$dst); + let InOperandList = (ins unknown:$src2); + let hasSideEffects = 0; +} + +//------------------------------------------------------------------------------ // Binary ops. //------------------------------------------------------------------------------ // Generic addition. diff --git a/llvm/include/llvm/Target/TargetOpcodes.def b/llvm/include/llvm/Target/TargetOpcodes.def index b17a949..cfb0649 100644 --- a/llvm/include/llvm/Target/TargetOpcodes.def +++ b/llvm/include/llvm/Target/TargetOpcodes.def @@ -168,6 +168,10 @@ HANDLE_TARGET_OPCODE(G_AND) /// Generic Bitwise-OR instruction. HANDLE_TARGET_OPCODE(G_OR) +/// Generic instruction to materialize the address of an alloca or other +/// stack-based object. +HANDLE_TARGET_OPCODE(G_FRAME_INDEX) + /// Generic BRANCH instruction. This is an unconditional branch. HANDLE_TARGET_OPCODE(G_BR) diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index e017b49..82cec25 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -15,6 +15,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/GlobalISel/CallLowering.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Function.h" @@ -43,7 +44,7 @@ unsigned IRTranslator::getOrCreateVReg(const Value &Val) { assert(Val.getType()->isSized() && "Don't know how to create an empty vreg"); assert(!Val.getType()->isAggregateType() && "Not yet implemented"); - unsigned Size = Val.getType()->getPrimitiveSizeInBits(); + unsigned Size = DL->getTypeSizeInBits(Val.getType()); unsigned VReg = MRI->createGenericVirtualRegister(Size); ValReg = VReg; assert(!isa(Val) && "Not yet implemented"); @@ -99,6 +100,23 @@ bool IRTranslator::translateBr(const Instruction &Inst) { return true; } +bool IRTranslator::translateStaticAlloca(const AllocaInst &AI) { + assert(AI.isStaticAlloca() && "only handle static allocas now"); + MachineFunction &MF = MIRBuilder.getMF(); + unsigned ElementSize = DL->getTypeStoreSize(AI.getAllocatedType()); + unsigned Size = + ElementSize * cast(AI.getArraySize())->getZExtValue(); + + unsigned Alignment = AI.getAlignment(); + if (!Alignment) + Alignment = DL->getABITypeAlignment(AI.getAllocatedType()); + + unsigned Res = getOrCreateVReg(AI); + int FI = MF.getFrameInfo()->CreateStackObject(Size, Alignment, false, &AI); + MIRBuilder.buildFrameIndex(LLT::pointer(0), Res, FI); + return true; +} + bool IRTranslator::translate(const Instruction &Inst) { MIRBuilder.setDebugLoc(Inst.getDebugLoc()); switch(Inst.getOpcode()) { @@ -107,17 +125,22 @@ bool IRTranslator::translate(const Instruction &Inst) { return translateBinaryOp(TargetOpcode::G_ADD, Inst); case Instruction::Sub: return translateBinaryOp(TargetOpcode::G_SUB, Inst); + // Bitwise operations. case Instruction::And: return translateBinaryOp(TargetOpcode::G_AND, Inst); case Instruction::Or: return translateBinaryOp(TargetOpcode::G_OR, Inst); + // Branch operations. case Instruction::Br: return translateBr(Inst); case Instruction::Ret: return translateReturn(Inst); + case Instruction::Alloca: + return translateStaticAlloca(cast(Inst)); + default: llvm_unreachable("Opcode not supported"); } @@ -138,6 +161,8 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &MF) { CLI = MF.getSubtarget().getCallLowering(); MIRBuilder.setMF(MF); MRI = &MF.getRegInfo(); + DL = &F.getParent()->getDataLayout(); + // Setup the arguments. MachineBasicBlock &MBB = getOrCreateBB(F.front()); MIRBuilder.setMBB(MBB); diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp index 382652f..220965c 100644 --- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -102,3 +102,11 @@ MachineInstr *MachineIRBuilder::buildInstr(unsigned Opcode, LLT Ty, MachineInstrBuilder(getMF(), NewMI).addMBB(&BB); return NewMI; } + +MachineInstr *MachineIRBuilder::buildFrameIndex(LLT Ty, unsigned Res, int Idx) { + MachineInstr *NewMI = buildInstr(TargetOpcode::G_FRAME_INDEX, Ty); + auto MIB = MachineInstrBuilder(getMF(), NewMI); + MIB.addReg(Res, RegState::Define); + MIB.addImm(Idx); + return NewMI; +} diff --git a/llvm/lib/CodeGen/LowLevelType.cpp b/llvm/lib/CodeGen/LowLevelType.cpp index 0f69622..c81535c 100644 --- a/llvm/lib/CodeGen/LowLevelType.cpp +++ b/llvm/lib/CodeGen/LowLevelType.cpp @@ -19,26 +19,32 @@ using namespace llvm; LLT::LLT(const Type &Ty) { if (auto VTy = dyn_cast(&Ty)) { - ScalarSize = VTy->getElementType()->getPrimitiveSizeInBits(); + SizeOrAddrSpace = VTy->getElementType()->getPrimitiveSizeInBits(); NumElements = VTy->getNumElements(); Kind = NumElements == 1 ? Scalar : Vector; + } else if (auto PTy = dyn_cast(&Ty)) { + Kind = Pointer; + SizeOrAddrSpace = PTy->getAddressSpace(); + NumElements = 1; } else if (Ty.isSized()) { // Aggregates are no different from real scalars as far as GlobalISel is // concerned. Kind = Scalar; - ScalarSize = Ty.getPrimitiveSizeInBits(); + SizeOrAddrSpace = Ty.getPrimitiveSizeInBits(); NumElements = 1; } else { Kind = Unsized; - ScalarSize = NumElements = 0; + SizeOrAddrSpace = NumElements = 0; } } void LLT::print(raw_ostream &OS) const { if (isVector()) - OS << "<" << NumElements << " x s" << ScalarSize << ">"; + OS << "<" << NumElements << " x s" << SizeOrAddrSpace << ">"; + else if (isPointer()) + OS << "p" << getAddressSpace(); else if (isSized()) - OS << "s" << ScalarSize; + OS << "s" << getScalarSizeInBits(); else if (isValid()) OS << "unsized"; else diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.cpp b/llvm/lib/CodeGen/MIRParser/MILexer.cpp index c9b4135f..503b52d 100644 --- a/llvm/lib/CodeGen/MIRParser/MILexer.cpp +++ b/llvm/lib/CodeGen/MIRParser/MILexer.cpp @@ -174,14 +174,18 @@ static Cursor lexName(Cursor C, MIToken &Token, MIToken::TokenKind Type, } static Cursor maybeLexIntegerOrScalarType(Cursor C, MIToken &Token) { - if ((C.peek() != 'i' && C.peek() != 's') || !isdigit(C.peek(1))) + if ((C.peek() != 'i' && C.peek() != 's' && C.peek() != 'p') || + !isdigit(C.peek(1))) return None; char Kind = C.peek(); auto Range = C; - C.advance(); // Skip 'i' + C.advance(); // Skip 'i', 's', or 'p' while (isdigit(C.peek())) C.advance(); - Token.reset(Kind == 'i' ? MIToken::IntegerType : MIToken::ScalarType, + + Token.reset(Kind == 'i' + ? MIToken::IntegerType + : (Kind == 's' ? MIToken::ScalarType : MIToken::PointerType), Range.upto(C)); return C; } diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.h b/llvm/lib/CodeGen/MIRParser/MILexer.h index a5a95f8..ea155c3 100644 --- a/llvm/lib/CodeGen/MIRParser/MILexer.h +++ b/llvm/lib/CodeGen/MIRParser/MILexer.h @@ -102,6 +102,7 @@ struct MIToken { NamedRegister, MachineBasicBlockLabel, MachineBasicBlock, + PointerType, ScalarType, StackObject, FixedStackObject, diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp index e4ca9ae..695c58d 100644 --- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp +++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp @@ -1030,7 +1030,7 @@ bool MIParser::parseLowLevelType(StringRef::iterator Loc, LLT &Ty, bool MustBeSized) { if (Token.is(MIToken::Identifier) && Token.stringValue() == "unsized") { if (MustBeSized) - return error(Loc, "expected sN or for sized GlobalISel type"); + return error(Loc, "expected pN, sN or for sized GlobalISel type"); lex(); Ty = LLT::unsized(); return false; @@ -1038,11 +1038,17 @@ bool MIParser::parseLowLevelType(StringRef::iterator Loc, LLT &Ty, Ty = LLT::scalar(APSInt(Token.range().drop_front()).getZExtValue()); lex(); return false; + } else if (Token.is(MIToken::PointerType)) { + Ty = LLT::pointer(APSInt(Token.range().drop_front()).getZExtValue()); + lex(); + return false; } // Now we're looking for a vector. if (Token.isNot(MIToken::less)) - return error(Loc, "expected unsized, sN or for GlobalISel type"); + return error(Loc, + "expected unsized, pN, sN or for GlobalISel type"); + lex(); if (Token.isNot(MIToken::IntegerLiteral)) diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll b/llvm/test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll index 721c98d..e02d463 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll @@ -17,6 +17,22 @@ define i64 @addi64(i64 %arg1, i64 %arg2) { ret i64 %res } +; Tests for alloca +; CHECK: name: allocai64 +; CHECK: stack: +; CHECK-NEXT: - { id: 0, name: ptr1, offset: 0, size: 8, alignment: 8 } +; CHECK-NEXT: - { id: 1, name: ptr2, offset: 0, size: 8, alignment: 1 } +; CHECK-NEXT: - { id: 2, name: ptr3, offset: 0, size: 128, alignment: 8 } +; CHECK: %{{[0-9]+}}(64) = G_FRAME_INDEX p0 0 +; CHECK: %{{[0-9]+}}(64) = G_FRAME_INDEX p0 1 +; CHECK: %{{[0-9]+}}(64) = G_FRAME_INDEX p0 2 +define void @allocai64() { + %ptr1 = alloca i64 + %ptr2 = alloca i64, align 1 + %ptr3 = alloca i64, i32 16 + ret void +} + ; Tests for br. ; CHECK: name: uncondbr ; CHECK: body: diff --git a/llvm/test/CodeGen/MIR/X86/generic-instr-type-error.mir b/llvm/test/CodeGen/MIR/X86/generic-instr-type-error.mir index 77ce5e5..b6ebb6c 100644 --- a/llvm/test/CodeGen/MIR/X86/generic-instr-type-error.mir +++ b/llvm/test/CodeGen/MIR/X86/generic-instr-type-error.mir @@ -10,6 +10,6 @@ registers: body: | bb.0.entry: liveins: %edi - ; CHECK: [[@LINE+1]]:16: expected sN or for sized GlobalISel type + ; CHECK: [[@LINE+1]]:16: expected pN, sN or for sized GlobalISel type %0 = G_ADD unsized %edi, %edi ...