| //===--- IRBuilder.h - Swift IR Builder -------------------------*- C++ -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines Swift's specialization of llvm::IRBuilder. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_IRGEN_IRBUILDER_H |
| #define SWIFT_IRGEN_IRBUILDER_H |
| |
| #include "llvm/ADT/PointerUnion.h" |
| #include "llvm/IR/IRBuilder.h" |
| #include "llvm/IR/InlineAsm.h" |
| #include "swift/Basic/LLVM.h" |
| #include "Address.h" |
| #include "IRGen.h" |
| |
| namespace swift { |
| namespace irgen { |
| class FunctionPointer; |
| class IRGenModule; |
| |
| using IRBuilderBase = llvm::IRBuilder<>; |
| |
| class IRBuilder : public IRBuilderBase { |
| public: |
| // Without this, it keeps resolving to llvm::IRBuilderBase because |
| // of the injected class name. |
| using IRBuilderBase = irgen::IRBuilderBase; |
| |
| private: |
| /// The block containing the insertion point when the insertion |
| /// point was last cleared. Used only for preserving block |
| /// ordering. |
| llvm::BasicBlock *ClearedIP; |
| unsigned NumTrapBarriers = 0; |
| |
| #ifndef NDEBUG |
| /// Whether debug information is requested. Only used in assertions. |
| bool DebugInfo; |
| #endif |
| |
| // Set calling convention of the call instruction using |
| // the same calling convention as the callee function. |
| // This ensures that they are always compatible. |
| void setCallingConvUsingCallee(llvm::CallInst *Call) { |
| auto CalleeFn = Call->getCalledFunction(); |
| if (CalleeFn) { |
| auto CC = CalleeFn->getCallingConv(); |
| Call->setCallingConv(CC); |
| } |
| } |
| |
| public: |
| IRBuilder(llvm::LLVMContext &Context, bool DebugInfo) |
| : IRBuilderBase(Context), ClearedIP(nullptr) |
| #ifndef NDEBUG |
| , DebugInfo(DebugInfo) |
| #endif |
| {} |
| |
| /// Determines if the current location is apparently reachable. The |
| /// invariant we maintain is that the insertion point of the builder |
| /// always points within a block unless the current location is |
| /// logically unreachable. All the low-level routines which emit |
| /// branches leave the insertion point in the original block, just |
| /// after the branch. High-level routines may then indicate |
| /// unreachability by clearing the insertion point. |
| bool hasValidIP() const { return GetInsertBlock() != nullptr; } |
| |
| /// Determines whether we're currently inserting after a terminator. |
| /// This is really just there for asserts. |
| bool hasPostTerminatorIP() const { |
| return GetInsertBlock() != nullptr && |
| !GetInsertBlock()->empty() && |
| isa<llvm::TerminatorInst>(GetInsertBlock()->back()); |
| } |
| |
| void ClearInsertionPoint() { |
| assert(hasValidIP() && "clearing invalid insertion point!"); |
| assert(ClearedIP == nullptr); |
| |
| /// Whenever we clear the insertion point, remember where we were. |
| ClearedIP = GetInsertBlock(); |
| IRBuilderBase::ClearInsertionPoint(); |
| } |
| |
| void SetInsertPoint(llvm::BasicBlock *BB) { |
| ClearedIP = nullptr; |
| IRBuilderBase::SetInsertPoint(BB); |
| } |
| |
| void SetInsertPoint(llvm::BasicBlock *BB, llvm::BasicBlock::iterator before) { |
| ClearedIP = nullptr; |
| IRBuilderBase::SetInsertPoint(BB, before); |
| } |
| |
| void SetInsertPoint(llvm::Instruction *I) { |
| ClearedIP = nullptr; |
| IRBuilderBase::SetInsertPoint(I); |
| } |
| |
| /// A stable insertion point in the function. "Stable" means that |
| /// it will point to the same location in the function, even if |
| /// instructions are subsequently added to the current basic block. |
| class StableIP { |
| /// Either an instruction that we're inserting after or the basic |
| /// block that we're inserting at the beginning of. |
| using UnionTy = llvm::PointerUnion<llvm::Instruction *, llvm::BasicBlock *>; |
| UnionTy After; |
| public: |
| StableIP() = default; |
| explicit StableIP(const IRBuilder &Builder) { |
| if (!Builder.hasValidIP()) { |
| After = UnionTy(); |
| assert(!isValid()); |
| return; |
| } |
| |
| llvm::BasicBlock *curBlock = Builder.GetInsertBlock(); |
| assert(Builder.GetInsertPoint() == curBlock->end()); |
| if (curBlock->empty()) |
| After = curBlock; |
| else |
| After = &curBlock->back(); |
| } |
| |
| /// Does this stable IP point to a valid location? |
| bool isValid() const { |
| return !After.isNull(); |
| } |
| |
| /// Insert an unparented instruction at this insertion point. |
| /// Note that inserting multiple instructions at an IP will cause |
| /// them to end up in reverse order. |
| void insert(llvm::Instruction *I) { |
| assert(isValid() && "inserting at invalid location!"); |
| assert(I->getParent() == nullptr); |
| if (auto *block = After.dyn_cast<llvm::BasicBlock*>()) { |
| block->getInstList().push_front(I); |
| } else { |
| llvm::Instruction *afterInsn = After.get<llvm::Instruction*>(); |
| afterInsn->getParent()->getInstList().insertAfter( |
| afterInsn->getIterator(), I); |
| } |
| } |
| |
| // Support for being placed in pointer unions. |
| void *getOpaqueValue() const { return After.getOpaqueValue(); } |
| static StableIP getFromOpaqueValue(void *p) { |
| StableIP result; |
| result.After = UnionTy::getFromOpaqueValue(p); |
| return result; |
| } |
| enum { NumLowBitsAvailable |
| = llvm::PointerLikeTypeTraits<UnionTy>::NumLowBitsAvailable }; |
| }; |
| |
| /// Capture a stable reference to the current IP. |
| StableIP getStableIP() const { |
| return StableIP(*this); |
| } |
| |
| /// Return the LLVM module we're inserting into. |
| llvm::Module *getModule() const { |
| if (auto BB = GetInsertBlock()) |
| return BB->getModule(); |
| assert(ClearedIP && "IRBuilder has no active or cleared insertion block"); |
| return ClearedIP->getModule(); |
| } |
| |
| /// Don't create allocas this way; you'll get a dynamic alloca. |
| /// Use IGF::createAlloca or IGF::emitDynamicAlloca. |
| llvm::Value *CreateAlloca(llvm::Type *type, llvm::Value *arraySize, |
| const llvm::Twine &name = "") = delete; |
| |
| llvm::LoadInst *CreateLoad(llvm::Value *addr, Alignment align, |
| const llvm::Twine &name = "") { |
| llvm::LoadInst *load = IRBuilderBase::CreateLoad(addr, name); |
| load->setAlignment(align.getValue()); |
| return load; |
| } |
| llvm::LoadInst *CreateLoad(Address addr, const llvm::Twine &name = "") { |
| return CreateLoad(addr.getAddress(), addr.getAlignment(), name); |
| } |
| |
| llvm::StoreInst *CreateStore(llvm::Value *value, llvm::Value *addr, |
| Alignment align) { |
| llvm::StoreInst *store = IRBuilderBase::CreateStore(value, addr); |
| store->setAlignment(align.getValue()); |
| return store; |
| } |
| llvm::StoreInst *CreateStore(llvm::Value *value, Address addr) { |
| return CreateStore(value, addr.getAddress(), addr.getAlignment()); |
| } |
| |
| // These are deleted because we want to force the caller to specify |
| // an alignment. |
| llvm::LoadInst *CreateLoad(llvm::Value *addr, |
| const llvm::Twine &name = "") = delete; |
| llvm::StoreInst *CreateStore(llvm::Value *value, llvm::Value *addr) = delete; |
| |
| using IRBuilderBase::CreateStructGEP; |
| Address CreateStructGEP(Address address, unsigned index, Size offset, |
| const llvm::Twine &name = "") { |
| llvm::Value *addr = CreateStructGEP( |
| address.getType()->getElementType(), address.getAddress(), |
| index, name); |
| return Address(addr, address.getAlignment().alignmentAtOffset(offset)); |
| } |
| Address CreateStructGEP(Address address, unsigned index, |
| const llvm::StructLayout *layout, |
| const llvm::Twine &name = "") { |
| Size offset = Size(layout->getElementOffset(index)); |
| return CreateStructGEP(address, index, offset, name); |
| } |
| |
| /// Given a pointer to an array element, GEP to the array element |
| /// N elements past it. The type is not changed. |
| Address CreateConstArrayGEP(Address base, unsigned index, Size eltSize, |
| const llvm::Twine &name = "") { |
| auto addr = CreateConstInBoundsGEP1_32( |
| base.getType()->getElementType(), base.getAddress(), index, name); |
| return Address(addr, |
| base.getAlignment().alignmentAtOffset(eltSize * index)); |
| } |
| |
| /// Given an i8*, GEP to N bytes past it. |
| Address CreateConstByteArrayGEP(Address base, Size offset, |
| const llvm::Twine &name = "") { |
| auto addr = CreateConstInBoundsGEP1_32( |
| base.getType()->getElementType(), base.getAddress(), offset.getValue(), |
| name); |
| return Address(addr, base.getAlignment().alignmentAtOffset(offset)); |
| } |
| |
| using IRBuilderBase::CreateBitCast; |
| Address CreateBitCast(Address address, llvm::Type *type, |
| const llvm::Twine &name = "") { |
| llvm::Value *addr = CreateBitCast(address.getAddress(), type, name); |
| return Address(addr, address.getAlignment()); |
| } |
| |
| /// Cast the given address to be a pointer to the given element type, |
| /// preserving the original address space. |
| Address CreateElementBitCast(Address address, llvm::Type *type, |
| const llvm::Twine &name = "") { |
| // Do nothing if the type doesn't change. |
| auto origPtrType = address.getType(); |
| if (origPtrType->getElementType() == type) return address; |
| |
| // Otherwise, cast to a pointer to the correct type. |
| auto ptrType = type->getPointerTo(origPtrType->getAddressSpace()); |
| return CreateBitCast(address, ptrType, name); |
| } |
| |
| /// Insert the given basic block after the IP block and move the |
| /// insertion point to it. Only valid if the IP is valid. |
| void emitBlock(llvm::BasicBlock *BB); |
| |
| using IRBuilderBase::CreateMemCpy; |
| llvm::CallInst *CreateMemCpy(Address dest, Address src, Size size) { |
| return CreateMemCpy(dest.getAddress(), dest.getAlignment().getValue(), |
| src.getAddress(), src.getAlignment().getValue(), |
| size.getValue()); |
| } |
| |
| using IRBuilderBase::CreateMemSet; |
| llvm::CallInst *CreateMemSet(Address dest, llvm::Value *value, Size size) { |
| return CreateMemSet(dest.getAddress(), value, size.getValue(), |
| dest.getAlignment().getValue()); |
| } |
| llvm::CallInst *CreateMemSet(Address dest, llvm::Value *value, |
| llvm::Value *size) { |
| return CreateMemSet(dest.getAddress(), value, size, |
| dest.getAlignment().getValue()); |
| } |
| |
| using IRBuilderBase::CreateLifetimeStart; |
| llvm::CallInst *CreateLifetimeStart(Address buf, Size size) { |
| return CreateLifetimeStart(buf.getAddress(), |
| llvm::ConstantInt::get(Context, APInt(64, size.getValue()))); |
| } |
| |
| using IRBuilderBase::CreateLifetimeEnd; |
| llvm::CallInst *CreateLifetimeEnd(Address buf, Size size) { |
| return CreateLifetimeEnd(buf.getAddress(), |
| llvm::ConstantInt::get(Context, APInt(64, size.getValue()))); |
| } |
| |
| // We're intentionally not allowing direct use of |
| // llvm::IRBuilder::CreateCall in order to push code towards using |
| // FunctionPointer. |
| |
| bool isTrapIntrinsic(llvm::Value *Callee) { |
| return Callee == llvm::Intrinsic::getDeclaration(getModule(), |
| llvm::Intrinsic::ID::trap); |
| } |
| bool isTrapIntrinsic(llvm::Intrinsic::ID intrinsicID) { |
| return intrinsicID == llvm::Intrinsic::ID::trap; |
| } |
| |
| llvm::CallInst *CreateCall(llvm::Value *Callee, ArrayRef<llvm::Value *> Args, |
| const Twine &Name = "", |
| llvm::MDNode *FPMathTag = nullptr) = delete; |
| |
| llvm::CallInst *CreateCall(llvm::FunctionType *FTy, llvm::Constant *Callee, |
| ArrayRef<llvm::Value *> Args, |
| const Twine &Name = "", |
| llvm::MDNode *FPMathTag = nullptr) { |
| assert((!DebugInfo || getCurrentDebugLocation()) && "no debugloc on call"); |
| assert(!isTrapIntrinsic(Callee) && "Use CreateNonMergeableTrap"); |
| auto Call = IRBuilderBase::CreateCall(FTy, Callee, Args, Name, FPMathTag); |
| setCallingConvUsingCallee(Call); |
| return Call; |
| } |
| |
| llvm::CallInst *CreateCall(llvm::Constant *Callee, |
| ArrayRef<llvm::Value *> Args, |
| const Twine &Name = "", |
| llvm::MDNode *FPMathTag = nullptr) { |
| // assert((!DebugInfo || getCurrentDebugLocation()) && "no debugloc on |
| // call"); |
| assert(!isTrapIntrinsic(Callee) && "Use CreateNonMergeableTrap"); |
| auto Call = IRBuilderBase::CreateCall(Callee, Args, Name, FPMathTag); |
| setCallingConvUsingCallee(Call); |
| return Call; |
| } |
| |
| llvm::CallInst *CreateCall(const FunctionPointer &fn, |
| ArrayRef<llvm::Value *> args); |
| |
| llvm::CallInst *CreateAsmCall(llvm::InlineAsm *asmBlock, |
| ArrayRef<llvm::Value *> args) { |
| return IRBuilderBase::CreateCall(asmBlock, args); |
| } |
| |
| /// Call an intrinsic with no type arguments. |
| llvm::CallInst *CreateIntrinsicCall(llvm::Intrinsic::ID intrinsicID, |
| ArrayRef<llvm::Value *> args, |
| const Twine &name = "") { |
| assert(!isTrapIntrinsic(intrinsicID) && "Use CreateNonMergeableTrap"); |
| auto intrinsicFn = |
| llvm::Intrinsic::getDeclaration(getModule(), intrinsicID); |
| return CreateCall(intrinsicFn, args, name); |
| } |
| |
| /// Call an intrinsic with type arguments. |
| llvm::CallInst *CreateIntrinsicCall(llvm::Intrinsic::ID intrinsicID, |
| ArrayRef<llvm::Type*> typeArgs, |
| ArrayRef<llvm::Value *> args, |
| const Twine &name = "") { |
| assert(!isTrapIntrinsic(intrinsicID) && "Use CreateNonMergeableTrap"); |
| auto intrinsicFn = |
| llvm::Intrinsic::getDeclaration(getModule(), intrinsicID, typeArgs); |
| return CreateCall(intrinsicFn, args, name); |
| } |
| |
| /// Call the trap intrinsic. If optimizations are enabled, an inline asm |
| /// gadget is emitted before the trap. The gadget inhibits transforms which |
| /// merge trap calls together, which makes debugging crashes easier. |
| llvm::CallInst *CreateNonMergeableTrap(IRGenModule &IGM); |
| |
| /// Split a first-class aggregate value into its component pieces. |
| template <unsigned N> |
| std::array<llvm::Value *, N> CreateSplit(llvm::Value *aggregate) { |
| assert(isa<llvm::StructType>(aggregate->getType())); |
| assert(cast<llvm::StructType>(aggregate->getType())->getNumElements() == N); |
| std::array<llvm::Value *, N> results; |
| for (unsigned i = 0; i != N; ++i) { |
| results[i] = CreateExtractValue(aggregate, i); |
| } |
| return results; |
| } |
| |
| /// Combine the given values into a first-class aggregate. |
| llvm::Value *CreateCombine(llvm::StructType *aggregateType, |
| ArrayRef<llvm::Value*> values) { |
| assert(aggregateType->getNumElements() == values.size()); |
| llvm::Value *result = llvm::UndefValue::get(aggregateType); |
| for (unsigned i = 0, e = values.size(); i != e; ++i) { |
| result = CreateInsertValue(result, values[i], i); |
| } |
| return result; |
| } |
| }; |
| |
| } // end namespace irgen |
| } // end namespace swift |
| |
| namespace llvm { |
| template <> struct PointerLikeTypeTraits<swift::irgen::IRBuilder::StableIP> { |
| using type = swift::irgen::IRBuilder::StableIP; |
| |
| public: |
| static void *getAsVoidPointer(type IP) { |
| return IP.getOpaqueValue(); |
| } |
| static type getFromVoidPointer(void *p) { |
| return type::getFromOpaqueValue(p); |
| } |
| |
| // The number of bits available are the min of the two pointer types. |
| enum { |
| NumLowBitsAvailable = type::NumLowBitsAvailable |
| }; |
| }; |
| } |
| |
| #endif |