diff options
Diffstat (limited to 'include/llvm')
39 files changed, 1235 insertions, 17 deletions
diff --git a/include/llvm/CodeGen/AsmPrinter.h b/include/llvm/CodeGen/AsmPrinter.h index 2920675231..b8d435ee13 100644 --- a/include/llvm/CodeGen/AsmPrinter.h +++ b/include/llvm/CodeGen/AsmPrinter.h @@ -94,6 +94,12 @@ namespace llvm { /// default, this is equal to CurrentFnSym. MCSymbol *CurrentFnSymForSize; + /// @LOCALMOD-BEGIN + /// Is the bitcode module a plain object? This is false + /// for shared (pso) and executable (pexe) files. + bool IsPlainObject; + /// @LOCALMOD-END + private: // GCMetadataPrinters - The garbage collection metadata printer table. void *GCMetadataPrinters; // Really a DenseMap. @@ -240,6 +246,18 @@ namespace llvm { // Targets can, or in the case of EmitInstruction, must implement these to // customize output. + // @LOCALMOD-START + /// UseReadOnlyJumpTables - true if JumpTableInfo must be in rodata. + virtual bool UseReadOnlyJumpTables() const { return false; } + /// GetTargetBasicBlockAlign - the target alignment for basic blocks. + virtual unsigned GetTargetBasicBlockAlign() const { return 0; } + /// GetTargetLabelAlign - Get optional alignment for TargetOpcode + /// labels E.g., EH_LABEL. + virtual unsigned GetTargetLabelAlign(const MachineInstr *MI) const { + return 0; + } + // @LOCALMOD-END + /// EmitStartOfAsmFile - This virtual method can be overridden by targets /// that want to emit something at the start of their file. virtual void EmitStartOfAsmFile(Module &) {} @@ -254,7 +272,12 @@ namespace llvm { /// EmitFunctionBodyEnd - Targets can override this to emit stuff after /// the last basic block in the function. - virtual void EmitFunctionBodyEnd() {} + virtual void EmitFunctionBodyEnd() { + // @LOCALMOD-START + unsigned NextFunctionAlignment = GetTargetBasicBlockAlign(); + if (NextFunctionAlignment) EmitAlignment(NextFunctionAlignment); + // @LOCALMOD-END + } /// EmitInstruction - Targets should implement this to emit instructions. virtual void EmitInstruction(const MachineInstr *) { diff --git a/include/llvm/CodeGen/CallingConvLower.h b/include/llvm/CodeGen/CallingConvLower.h index 3afe3095d4..59e7520d24 100644 --- a/include/llvm/CodeGen/CallingConvLower.h +++ b/include/llvm/CodeGen/CallingConvLower.h @@ -164,6 +164,7 @@ private: SmallVector<uint32_t, 16> UsedRegs; unsigned FirstByValReg; bool FirstByValRegValid; + bool HasByValInRegPosition; // @LOCALMOD -- ARM only: see comment below. protected: ParmContext CallOrPrologue; @@ -311,6 +312,19 @@ public: void clearFirstByValReg() { FirstByValReg = 0; FirstByValRegValid = false; } bool isFirstByValRegValid() const { return FirstByValRegValid; } + // @LOCALMOD-BEGIN + // We disabled the splitting of byval between registers and memory. + // This separate flag indicates that a byval existed. We cannot reuse + // isFirstByValRegValid() because that is already used by the broken + // mechanism of splitting between stack and regs. We should check + // again if this mechanism is still broken later, or try to fix that + // mechanism. + // NOTE: this is only for ARM, so should be refactored. + bool hasByValInRegPosition() const { return HasByValInRegPosition; } + void setHasByValInRegPosition() { HasByValInRegPosition = true; } + void clearHasByValInRegPosition() { HasByValInRegPosition = false; } + // @LOCALMOD-END + ParmContext getCallOrPrologue() const { return CallOrPrologue; } private: diff --git a/include/llvm/CodeGen/ISDOpcodes.h b/include/llvm/CodeGen/ISDOpcodes.h index 5d0a3b4c70..95aafb324d 100644 --- a/include/llvm/CodeGen/ISDOpcodes.h +++ b/include/llvm/CodeGen/ISDOpcodes.h @@ -641,6 +641,16 @@ namespace ISD { /// is the chain and the second operand is the alloca pointer. LIFETIME_START, LIFETIME_END, + // @LOCALMOD-BEGIN + // NACL_* - Native Client instrinsics. + // These correspond to functions in: + // native_client/src/untrusted/nacl/tls_params.h + NACL_TP_TLS_OFFSET, + NACL_TP_TDB_OFFSET, + // Expands to the target architecture enumeration value. + NACL_TARGET_ARCH, + // @LOCALMOD-END + /// BUILTIN_OP_END - This must be the last enum value in this list. /// The target-specific pre-isel opcode values start here. BUILTIN_OP_END diff --git a/include/llvm/CodeGen/IntrinsicLowering.h b/include/llvm/CodeGen/IntrinsicLowering.h index 767b666225..c5ffc7ec0e 100644 --- a/include/llvm/CodeGen/IntrinsicLowering.h +++ b/include/llvm/CodeGen/IntrinsicLowering.h @@ -16,6 +16,7 @@ #ifndef LLVM_CODEGEN_INTRINSICLOWERING_H #define LLVM_CODEGEN_INTRINSICLOWERING_H +#include "llvm/ADT/StringSet.h" // @LOCALMOD #include "llvm/Intrinsics.h" namespace llvm { @@ -26,12 +27,23 @@ namespace llvm { class IntrinsicLowering { const TargetData& TD; - + static StringSet<> FuncNames; // @LOCALMOD + bool Warned; public: explicit IntrinsicLowering(const TargetData &td) : TD(td), Warned(false) {} + /// @LOCALMOD-BEGIN + /// GetFuncNames - Get the names of all functions which may + /// be called by an intrinsic. + static const StringSet<> &GetFuncNames(); + + /// IsCalledByIntrinsic - Returns true if a function may be called + /// by an intrinsic. + static bool IsCalledByIntrinsic(const StringRef &FuncName); + /// @LOCALMOD-END + /// AddPrototypes - This method, if called, causes all of the prototypes /// that might be needed by an intrinsic lowering implementation to be /// inserted into the module specified. diff --git a/include/llvm/CodeGen/JITCodeEmitter.h b/include/llvm/CodeGen/JITCodeEmitter.h index 89f00e91f7..f95b8b6b84 100644 --- a/include/llvm/CodeGen/JITCodeEmitter.h +++ b/include/llvm/CodeGen/JITCodeEmitter.h @@ -290,7 +290,7 @@ public: /// getCurrentPCOffset - Return the offset from the start of the emitted /// buffer that we are currently writing to. - uintptr_t getCurrentPCOffset() const { + virtual uintptr_t getCurrentPCOffset() const { // @LOCALMOD return CurBufferPtr-BufferBegin; } @@ -335,6 +335,13 @@ public: /// getLabelLocations - Return the label locations map of the label IDs to /// their address. virtual DenseMap<MCSymbol*, uintptr_t> *getLabelLocations() { return 0; } + + // @LOCALMOD-START + virtual void beginBundleLock() {}; + virtual void endBundleLock() {}; + virtual void alignToBundleBeginning() {}; + virtual void alignToBundleEnd() {}; + // @LOCALMOD-END }; } // End llvm namespace diff --git a/include/llvm/CodeGen/LexicalScopes.h b/include/llvm/CodeGen/LexicalScopes.h index 8414c64544..e1911cfd82 100644 --- a/include/llvm/CodeGen/LexicalScopes.h +++ b/include/llvm/CodeGen/LexicalScopes.h @@ -162,6 +162,12 @@ public: #ifndef NDEBUG IndentLevel = 0; #endif + // @LOCALMOD-BEGIN -- Hack for bug + // http://code.google.com/p/nativeclient/issues/detail?id=2786 + Desc.make_weak(); + InlinedAtLocation.make_weak(); + // @LOCALMOD-END + if (Parent) Parent->addChild(this); } diff --git a/include/llvm/CodeGen/MachineConstantPool.h b/include/llvm/CodeGen/MachineConstantPool.h index d6d65a24de..b0a70a872e 100644 --- a/include/llvm/CodeGen/MachineConstantPool.h +++ b/include/llvm/CodeGen/MachineConstantPool.h @@ -57,6 +57,17 @@ public: virtual void addSelectionDAGCSEId(FoldingSetNodeID &ID) = 0; + // @LOCALMOD-START + /// getJumpTableIndex - Check if this is a reference to a jump table. + /// If so, return a pointer to the jump table index value that is stored + /// in the constant pool, else return 0. + /// The default behavior is to indicate that the value is not a jump table + /// index. This is used by BranchFolder::runOnMachineFunction() and only in + /// conjunction with ARM targets + /// TODO: this should be cleaned up as it does tripple duty: tester, setter, getter + virtual unsigned *getJumpTableIndex() { return 0; } + // @LOCALMOD-END + /// print - Implement operator<< virtual void print(raw_ostream &O) const = 0; }; diff --git a/include/llvm/CodeGen/MachineInstrBuilder.h b/include/llvm/CodeGen/MachineInstrBuilder.h index 654361f9d4..c023d8815b 100644 --- a/include/llvm/CodeGen/MachineInstrBuilder.h +++ b/include/llvm/CodeGen/MachineInstrBuilder.h @@ -282,6 +282,21 @@ inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, return BuildMI(BB, MII, DL, MCID); } +// @LOCALMOD-BEGIN +/// BuildMI - This version of the builder inserts the newly-built +/// instruction before the given position in the given MachineBasicBlock, +/// does NOT take a destination register, and does not add implicit operands. +/// +inline MachineInstrBuilder BuildMI_NoImp(MachineBasicBlock &BB, + MachineBasicBlock::iterator I, + DebugLoc DL, + const MCInstrDesc &MCID) { + MachineInstr *MI = BB.getParent()->CreateMachineInstr(MCID, DL, true); + BB.insert(I, MI); + return MachineInstrBuilder(MI); +} +// @LOCALMOD-END + /// BuildMI - This version of the builder inserts the newly-built /// instruction at the end of the given MachineBasicBlock, and does NOT take a /// destination register. diff --git a/include/llvm/CodeGen/MachineRelocation.h b/include/llvm/CodeGen/MachineRelocation.h index 244b466e17..8d71930882 100644 --- a/include/llvm/CodeGen/MachineRelocation.h +++ b/include/llvm/CodeGen/MachineRelocation.h @@ -197,6 +197,14 @@ public: return Offset; } + // @LOCALMOD-START + /// setMachineCodeOffset() - Adjust the offset in the code buffer (this is + /// used when the instruction is moved after emission for bundle alignment) + void setMachineCodeOffset(intptr_t offset) { + Offset = offset; + } + // @LOCALMOD-END + /// getRelocationType - Return the target-specific relocation ID for this /// relocation. unsigned getRelocationType() const { diff --git a/include/llvm/ExecutionEngine/NaClJITMemoryManager.h b/include/llvm/ExecutionEngine/NaClJITMemoryManager.h new file mode 100644 index 0000000000..dcd06627df --- /dev/null +++ b/include/llvm/ExecutionEngine/NaClJITMemoryManager.h @@ -0,0 +1,237 @@ +//=-- NaClJITMemoryManager.h - Interface JIT uses to Allocate Mem -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_EXECUTION_ENGINE_NACL_JIT_MEMMANAGER_H +#define LLVM_EXECUTION_ENGINE_NACL_JIT_MEMMANAGER_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ExecutionEngine/JITMemoryManager.h" +#include "llvm/Support/Allocator.h" + +namespace llvm { + +class Function; +class GlobalValue; + +struct SimpleSlab { + uint8_t *address; + size_t size; + uint8_t *next_free; +}; + +struct FreeListNode { + uint8_t *address; + uintptr_t size; + FreeListNode *Prev; + FreeListNode *Next; + FreeListNode *RemoveFromFreeList() { + assert(Next->Prev == this && Prev->Next == this && "Freelist broken!"); + Next->Prev = Prev; + return Prev->Next = Next; + } + void AddToFreeList(FreeListNode *FreeList) { + Next = FreeList; + Prev = FreeList->Prev; + Prev->Next = this; + Next->Prev = this; + } +}; + +class NaClJITMemoryManager : public JITMemoryManager { + // NaCl disallows writing into any code region, and disallows executing any + // data region. Thus we can never get any RWX memory and the the strategy + // used by the other allocators of colocation of allocation metadata + // with the allocated code won't work. + // Currently with NaCl we have one single pool of usable space between the + // text and rodata segments, defined by the linker + // so to support stub allocation in the middle of a function, we allocate + // them in slabs interspersed with the functions. + + static const size_t kStubSlabSize = 16 * 1024; + static const size_t kDataSlabSize = 16 * 1024; + static const size_t kCodeSlabSize = 64 * 1024; + + typedef DenseMap<uint8_t *, size_t> AllocationTable; + + uint8_t *AllocatableRegionStart; + uint8_t *AllocatableRegionLimit; + uint8_t *NextCode; + SimpleSlab CurrentStubSlab; + + // Allocation metadata must be kept separate from code, so the free list is + // allocated with new rather than being a header in the code blocks + FreeListNode *CodeFreeListHead; + FreeListNode *CurrentCodeBlock; + // Mapping from pointer to allocated function, to size of allocation + AllocationTable AllocatedFunctions; + + // Since Exception tables are allocated like functions (i.e. we don't know + // ahead of time how large they are) we use the same allocation method for + // simplicity even though it's not strictly necessary to separate the + // allocation metadata from the allocated data. + FreeListNode *DataFreeListHead; + FreeListNode *CurrentDataBlock; + AllocationTable AllocatedTables; + BumpPtrAllocator DataAllocator; + + uint8_t *GOTBase; // Target Specific reserved memory + + FreeListNode *allocateCodeSlab(size_t MinSize); + FreeListNode *allocateDataSlab(size_t MinSize); + SimpleSlab allocateStubSlab(size_t MinSize); + + // Functions for allocations using one of the free lists + void InitFreeList(FreeListNode **Head); + void DestroyFreeList(FreeListNode *Head); + FreeListNode *FreeListAllocate(uintptr_t &ActualSize, FreeListNode *Head, + FreeListNode * (NaClJITMemoryManager::*allocate)(size_t)); + void FreeListFinishAllocation(FreeListNode *Block, FreeListNode *Head, + uint8_t *AllocationStart, uint8_t *AllocationEnd, AllocationTable &table); + void FreeListDeallocate(FreeListNode *Head, AllocationTable &Table, + void *Body); + public: + // TODO(dschuff): how to find the real value? is it a flag? + static const int kBundleSize = 32; + static const intptr_t kJumpMask = -32; + NaClJITMemoryManager(); + virtual ~NaClJITMemoryManager(); + static inline bool classof(const JITMemoryManager*) { return true; } + + /// setMemoryWritable - No-op on NaCl - code is never writable + virtual void setMemoryWritable() {} + + /// setMemoryExecutable - No-op on NaCl - data is never executable + virtual void setMemoryExecutable() {} + + /// setPoisonMemory - No-op on NaCl - nothing unvalidated is ever executable + virtual void setPoisonMemory(bool poison) {} + + /// getPointerToNamedFunction - This method returns the address of the + /// specified function. As such it is only useful for resolving library + /// symbols, not code generated symbols. + /// + /// If AbortOnFailure is false and no function with the given name is + /// found, this function silently returns a null pointer. Otherwise, + /// it prints a message to stderr and aborts. + /// + virtual void *getPointerToNamedFunction(const std::string &Name, + bool AbortOnFailure = true) ; + + //===--------------------------------------------------------------------===// + // Global Offset Table Management + //===--------------------------------------------------------------------===// + + /// AllocateGOT - If the current table requires a Global Offset Table, this + /// method is invoked to allocate it. This method is required to set HasGOT + /// to true. + virtual void AllocateGOT(); + + /// getGOTBase - If this is managing a Global Offset Table, this method should + /// return a pointer to its base. + virtual uint8_t *getGOTBase() const { + return GOTBase; + } + + //===--------------------------------------------------------------------===// + // Main Allocation Functions + //===--------------------------------------------------------------------===// + + /// startFunctionBody - When we start JITing a function, the JIT calls this + /// method to allocate a block of free RWX memory, which returns a pointer to + /// it. If the JIT wants to request a block of memory of at least a certain + /// size, it passes that value as ActualSize, and this method returns a block + /// with at least that much space. If the JIT doesn't know ahead of time how + /// much space it will need to emit the function, it passes 0 for the + /// ActualSize. In either case, this method is required to pass back the size + /// of the allocated block through ActualSize. The JIT will be careful to + /// not write more than the returned ActualSize bytes of memory. + virtual uint8_t *startFunctionBody(const Function *F, + uintptr_t &ActualSize); + + /// allocateStub - This method is called by the JIT to allocate space for a + /// function stub (used to handle limited branch displacements) while it is + /// JIT compiling a function. For example, if foo calls bar, and if bar + /// either needs to be lazily compiled or is a native function that exists too + /// far away from the call site to work, this method will be used to make a + /// thunk for it. The stub should be "close" to the current function body, + /// but should not be included in the 'actualsize' returned by + /// startFunctionBody. + virtual uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize, + unsigned Alignment); + + /// endFunctionBody - This method is called when the JIT is done codegen'ing + /// the specified function. At this point we know the size of the JIT + /// compiled function. This passes in FunctionStart (which was returned by + /// the startFunctionBody method) and FunctionEnd which is a pointer to the + /// actual end of the function. This method should mark the space allocated + /// and remember where it is in case the client wants to deallocate it. + virtual void endFunctionBody(const Function *F, uint8_t *FunctionStart, + uint8_t *FunctionEnd); + + /// allocateCodeSection - Allocate a memory block of (at least) the given + /// size suitable for executable code. The SectionID is a unique identifier + /// assigned by the JIT and passed through to the memory manager for + /// the instance class to use if it needs to communicate to the JIT about + /// a given section after the fact. + virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID); + + /// allocateDataSection - Allocate a memory block of (at least) the given + /// size suitable for data. The SectionID is a unique identifier + /// assigned by the JIT and passed through to the memory manager for + /// the instance class to use if it needs to communicate to the JIT about + /// a given section after the fact. + virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID); + + /// allocateSpace - Allocate a memory block of the given size. This method + /// cannot be called between calls to startFunctionBody and endFunctionBody. + virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment); + + /// allocateGlobal - Allocate memory for a global. + virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment); + + /// deallocateFunctionBody - Free the specified function body. The argument + /// must be the return value from a call to startFunctionBody() that hasn't + /// been deallocated yet. This is never called when the JIT is currently + /// emitting a function. + virtual void deallocateFunctionBody(void *Body); + + /// startExceptionTable - When we finished JITing the function, if exception + /// handling is set, we emit the exception table. + virtual uint8_t* startExceptionTable(const Function* F, + uintptr_t &ActualSize); + + /// endExceptionTable - This method is called when the JIT is done emitting + /// the exception table. + virtual void endExceptionTable(const Function *F, uint8_t *TableStart, + uint8_t *TableEnd, uint8_t* FrameRegister); + + /// deallocateExceptionTable - Free the specified exception table's memory. + /// The argument must be the return value from a call to startExceptionTable() + /// that hasn't been deallocated yet. This is never called when the JIT is + /// currently emitting an exception table. + virtual void deallocateExceptionTable(void *ET); + + virtual size_t GetDefaultCodeSlabSize() { + return kCodeSlabSize; + } + virtual size_t GetDefaultDataSlabSize() { + return kDataSlabSize; + } + virtual size_t GetDefaultStubSlabSize() { + return kStubSlabSize; + } + +}; + +} + +#endif // LLVM_EXECUTION_ENGINE_NACL_JIT_MEMMANAGER_H diff --git a/include/llvm/GlobalValue.h b/include/llvm/GlobalValue.h index 58d02576c1..bd193b97c9 100644 --- a/include/llvm/GlobalValue.h +++ b/include/llvm/GlobalValue.h @@ -76,6 +76,26 @@ public: removeDeadConstantUsers(); // remove any dead constants using this. } + // @LOCALMOD-BEGIN + /// Set the symbol version for this definition. + void setVersionDef(StringRef Version, bool IsDefault); + + /// Set the symbol version and dynamic source file (soname) + /// for this exterally provided global. + void setNeeded(StringRef Version, StringRef DynFile); + + /// Get the name of this symbol without the version suffix. + StringRef getUnversionedName() const; + + /// Get the version of this symbol. + /// Returns an empty string if the symbol is unversioned. + StringRef getVersion() const; + + /// Returns true if this is the default version of the symbol. + /// This may only be called if the symbol is versioned. + bool isDefaultVersion() const; + // @LOCALMOD-END + unsigned getAlignment() const { return (1u << Alignment) >> 1; } diff --git a/include/llvm/InitializePasses.h b/include/llvm/InitializePasses.h index 76c22b0fb8..4c93d480dd 100644 --- a/include/llvm/InitializePasses.h +++ b/include/llvm/InitializePasses.h @@ -261,6 +261,7 @@ void initializeUnpackMachineBundlesPass(PassRegistry&); void initializeFinalizeMachineBundlesPass(PassRegistry&); void initializeBBVectorizePass(PassRegistry&); void initializeMachineFunctionPrinterPassPass(PassRegistry&); +void initializeNaClCcRewritePass(PassRegistry&); // @LOCALMOD } #endif diff --git a/include/llvm/Intrinsics.td b/include/llvm/Intrinsics.td index 804db49556..d960f8c789 100644 --- a/include/llvm/Intrinsics.td +++ b/include/llvm/Intrinsics.td @@ -457,6 +457,32 @@ def int_convertus : Intrinsic<[llvm_anyint_ty], def int_convertuu : Intrinsic<[llvm_anyint_ty], [llvm_anyint_ty, llvm_i32_ty, llvm_i32_ty]>; +// @LOCALMOD-BEGIN +//===----------------------- Native Client Intrinsics ---------------------===// +// TODO(sehr): conditionalize this on IsNaCl64 | IsNaCl32 | IsNaClArm. +// The expansions of these are in lib/Target/X86/X86InstrNacl.{td, cpp} and +// lib/Target/ARM/ARMInstrInfo.td. +def int_nacl_setjmp : Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_ptr_ty]>, + GCCBuiltin<"__builtin_nacl_setjmp">; +def int_nacl_longjmp : Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty]>, + GCCBuiltin<"__builtin_nacl_longjmp">; + +// The following intrinsics provide target-specific implementations of +// the interface in native_client/src/untrusted/nacl/tls_params.h. +// The intrinsic names are basically the functions there without the +// leading underscores. +def int_nacl_tp_tls_offset : Intrinsic<[llvm_i32_ty], [llvm_i32_ty]>, + GCCBuiltin<"__builtin_nacl_tp_tls_offset">; +def int_nacl_tp_tdb_offset : Intrinsic<[llvm_i32_ty], [llvm_i32_ty]>, + GCCBuiltin<"__builtin_nacl_tp_tdb_offset">; + +// The following intrinsic provides a target-specific constant value to +// indicate the target platform compiled to. The enum values are enumerated +// pnaclintrin.h. +def int_nacl_target_arch : Intrinsic<[llvm_i32_ty], []>, + GCCBuiltin<"__builtin_nacl_target_arch">; +// @LOCALMOD-END + //===----------------------------------------------------------------------===// // Target-specific intrinsics //===----------------------------------------------------------------------===// diff --git a/include/llvm/MC/MCAsmBackend.h b/include/llvm/MC/MCAsmBackend.h index 348a5f52d2..ebe5542555 100644 --- a/include/llvm/MC/MCAsmBackend.h +++ b/include/llvm/MC/MCAsmBackend.h @@ -25,6 +25,7 @@ class MCInst; class MCInstFragment; class MCObjectWriter; class MCSection; +class MCStreamer; class MCValue; class raw_ostream; @@ -150,6 +151,23 @@ public: /// handleAssemblerFlag - Handle any target-specific assembler flags. /// By default, do nothing. virtual void handleAssemblerFlag(MCAssemblerFlag Flag) {} + + // @LOCALMOD-BEGIN + /// getBundleSize - Return the size (in bytes) of code bundling units + /// for this target. If 0, bundling is disabled. This is used exclusively + /// for Native Client. + virtual unsigned getBundleSize() const { + return 0; + } + + /// CustomExpandInst - + /// If the MCInst instruction has a custom expansion, write it to the + /// MCStreamer 'Out'. This can be used to perform "last minute" rewrites of + /// MCInst instructions for emission. + virtual bool CustomExpandInst(const MCInst &Inst, MCStreamer &Out) const { + return false; + } + // @LOCALMOD-END }; } // End llvm namespace diff --git a/include/llvm/MC/MCAsmInfo.h b/include/llvm/MC/MCAsmInfo.h index 97aad71fd9..29ec1020c3 100644 --- a/include/llvm/MC/MCAsmInfo.h +++ b/include/llvm/MC/MCAsmInfo.h @@ -48,6 +48,14 @@ namespace llvm { /// Default is 4. unsigned PointerSize; + /// @LOCALMOD-BEGIN + /// TODO(pdox): Before upstreaming this, make sure every target backend + /// sets it correctly. + /// StackSlotSize - Stack slot size in bytes. + /// Default is 4. + unsigned StackSlotSize; + /// @LOCALMOD-END + /// IsLittleEndian - True if target is little endian. /// Default is true. bool IsLittleEndian; @@ -340,6 +348,13 @@ namespace llvm { return PointerSize; } + /// @LOCALMOD-BEGIN + /// getStackSlotSize - Get the stack slot size in bytes. + unsigned getStackSlotSize() const { + return StackSlotSize; + } + /// @LOCALMOD-END + /// islittleendian - True if the target is little endian. bool isLittleEndian() const { return IsLittleEndian; diff --git a/include/llvm/MC/MCAsmLayout.h b/include/llvm/MC/MCAsmLayout.h index cf79216d07..fdded4ffa7 100644 --- a/include/llvm/MC/MCAsmLayout.h +++ b/include/llvm/MC/MCAsmLayout.h @@ -80,6 +80,11 @@ public: /// \brief Get the offset of the given fragment inside its containing section. uint64_t getFragmentOffset(const MCFragment *F) const; + // @LOCALMOD-BEGIN + /// \brief Get the bundle padding of the given fragment. + uint8_t getFragmentPadding(const MCFragment *F) const; + // @LOCALMOD-END + /// @} /// @name Utility Functions /// @{ diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index 83c01ec5b9..6fc685cb33 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -52,11 +52,39 @@ public: FT_Org, FT_Dwarf, FT_DwarfFrame, - FT_LEB + FT_LEB, + FT_Tiny // @LOCALMOD }; + // @LOCALMOD-BEGIN + enum BundleAlignType { + BundleAlignNone = 0, + BundleAlignStart = 1, + BundleAlignEnd = 2 + }; + // @LOCALMOD-END + private: - FragmentType Kind; + // @LOCALMOD-BEGIN + // Try to compress the layout of MCFragment by: + // 1) Making Kind, the bundling flags, and BundlePadding fit in 32 bits. + // 2) Move LayoutOrder to fit in the hole left by aligning for 64 bits. + + FragmentType Kind : 4; + + BundleAlignType BundleAlign : 2; + bool BundleGroupStart : 1; + bool BundleGroupEnd : 1; + + /// BundlePadding - The computed padding for this fragment. This is ~0 + /// until initialized. + uint8_t BundlePadding; + + /// LayoutOrder - The layout order of this fragment. + unsigned LayoutOrder; + + // @LOCALMOD-END + /// Parent - The data for the section this fragment is in. MCSectionData *Parent; @@ -75,9 +103,6 @@ private: /// initialized. uint64_t Offset; - /// LayoutOrder - The layout order of this fragment. - unsigned LayoutOrder; - /// @} protected: @@ -99,14 +124,46 @@ public: unsigned getLayoutOrder() const { return LayoutOrder; } void setLayoutOrder(unsigned Value) { LayoutOrder = Value; } + // @LOCALMOD-BEGIN + bool isBundleGroupStart() const { return BundleGroupStart; } + void setBundleGroupStart(bool Value) { BundleGroupStart = Value; } + + bool isBundleGroupEnd() const { return BundleGroupEnd; } + void setBundleGroupEnd(bool Value) { BundleGroupEnd = Value; } + + BundleAlignType getBundleAlign() const { return BundleAlign; } + void setBundleAlign(BundleAlignType Value) { BundleAlign = Value; } + // @LOCALMOD-END + static bool classof(const MCFragment *O) { return true; } void dump(); }; +// @LOCALMOD-BEGIN +// This is just a tiny data fragment with no fixups. +// (To help with memory usage) +class MCTinyFragment : public MCFragment { + private: + SmallString<6> Contents; + + public: + + MCTinyFragment(MCSectionData *SD = 0) : MCFragment(FT_Tiny, SD) {} + + SmallString<6> &getContents() { return Contents; } + const SmallString<6> &getContents() const { return Contents; } + + static bool classof(const MCFragment *F) { + return F->getKind() == MCFragment::FT_Tiny; + } + static bool classof(const MCTinyFragment *) { return true; } +}; +// @LOCALMOD-END + class MCDataFragment : public MCFragment { virtual void anchor(); - SmallString<32> Contents; + SmallString<6> Contents; // @LOCALMOD: Memory efficiency /// Fixups - The list of fixups in this fragment. std::vector<MCFixup> Fixups; @@ -121,8 +178,8 @@ public: /// @name Accessors /// @{ - SmallString<32> &getContents() { return Contents; } - const SmallString<32> &getContents() const { return Contents; } + SmallString<6> &getContents() { return Contents; } // @LOCALMOD + const SmallString<6> &getContents() const { return Contents; } // @LOCALMOD /// @} /// @name Fixup Access @@ -474,6 +531,29 @@ private: /// it. unsigned HasInstructions : 1; + // @LOCALMOD-BEGIN + bool BundlingEnabled : 1; + bool BundleLocked : 1; + + // Because ".bundle_lock" occurs before the fragment it applies to exists, + // we need to keep this flag around so we know to mark the next fragment + // as the start of a bundle group. A similar flag is not necessary for the + // last fragment, because when a .bundle_unlock occurs, the last fragment + // in the group already exists and can be marked directly. + bool BundleGroupFirstFrag : 1; + + typedef MCFragment::BundleAlignType BundleAlignType; + BundleAlignType BundleAlignNext : 2; + + // Optimization to reduce the number of fragments generated (for memory + // savings). Keep track of when we know the offset of the next point to + // emit an instruction. If we know the offset from a known alignment point, + // we can just append to the previous fragment. + bool BundleOffsetKnown : 1; + unsigned BundleSize; + unsigned BundleOffset; + // @LOCALMOD-END + /// @} public: @@ -495,6 +575,25 @@ public: unsigned getLayoutOrder() const { return LayoutOrder; } void setLayoutOrder(unsigned Value) { LayoutOrder = Value; } + // @LOCALMOD-BEGIN + bool isBundlingEnabled() const { return BundlingEnabled; } + + bool isBundleLocked() const { return BundleLocked; } + void setBundleLocked(bool Value) { BundleLocked = Value; } + + bool isBundleGroupFirstFrag() const { return BundleGroupFirstFrag; } + void setBundleGroupFirstFrag(bool Value) { BundleGroupFirstFrag = Value; } + + + BundleAlignType getBundleAlignNext() const { return BundleAlignNext; } + void setBundleAlignNext(BundleAlignType Value) { BundleAlignNext = Value; } + + void MarkBundleOffsetUnknown(); + bool ShouldCreateNewFragment(size_t Size); + void UpdateBundleOffset(size_t Size); + void AlignBundleOffsetTo(size_t AlignBase); + // @LOCALMOD-END + /// @name Fragment Access /// @{ @@ -753,6 +852,13 @@ private: bool fragmentNeedsRelaxation(const MCInstFragment *IF, const MCAsmLayout &Layout) const; + // @LOCALMOD-BEGIN + uint8_t ComputeBundlePadding(const MCAsmLayout &Layout, + MCFragment *F, + uint64_t FragmentOffset) const; + // @LOCALMOD-END + + /// layoutOnce - Perform one layout iteration and return true if any offsets /// were adjusted. bool layoutOnce(MCAsmLayout &Layout); @@ -819,6 +925,12 @@ public: MCAsmBackend &getBackend() const { return Backend; } + // @LOCALMOD-BEGIN + uint64_t getBundleSize() const; + uint64_t getBundleMask() const; + // @LOCALMOD-END + + MCCodeEmitter &getEmitter() const { return Emitter; } MCObjectWriter &getWriter() const { return Writer; } diff --git a/include/llvm/MC/MCELFObjectWriter.h b/include/llvm/MC/MCELFObjectWriter.h index abbe188fe8..688c8a9575 100644 --- a/include/llvm/MC/MCELFObjectWriter.h +++ b/include/llvm/MC/MCELFObjectWriter.h @@ -69,6 +69,12 @@ public: return ELF::ELFOSABI_FREEBSD; case Triple::Linux: return ELF::ELFOSABI_LINUX; + // @LOCALMOD-BEGIN + // This shouldn't be needed anymore (sel_ldr doesn't check for it), + // but removing it may require some changes in binutils also. + case Triple::NativeClient: + return ELF::ELFOSABI_NACL; + // @LOCALMOD-END default: return ELF::ELFOSABI_NONE; } diff --git a/include/llvm/MC/MCObjectStreamer.h b/include/llvm/MC/MCObjectStreamer.h index b59b76c2be..466773bc0a 100644 --- a/include/llvm/MC/MCObjectStreamer.h +++ b/include/llvm/MC/MCObjectStreamer.h @@ -68,6 +68,14 @@ public: unsigned AddrSpace); virtual void EmitULEB128Value(const MCExpr *Value); virtual void EmitSLEB128Value(const MCExpr *Value); + + // @LOCALMOD-BEGIN + void EmitBundleLock(); + void EmitBundleUnlock(); + void EmitBundleAlignStart(); + void EmitBundleAlignEnd(); + // @LOCALMOD-END + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); virtual void ChangeSection(const MCSection *Section); virtual void EmitInstruction(const MCInst &Inst); diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index 44698989c1..ad30b9ca60 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -467,6 +467,27 @@ namespace llvm { /// @} + // @LOCALMOD-BEGIN + /// @name Bundling Directives + /// @{ + + /// EmitBundleLock - Begin a group of instructions which cannot + /// cross a bundle boundary. + virtual void EmitBundleLock() = 0; + + /// EmitBundleUnlock - End a bundle-locked group of instructions. + virtual void EmitBundleUnlock() = 0; + + /// EmitBundleAlignStart - Guarantee that the next instruction or + /// bundle-locked group starts at the beginning of a bundle. + virtual void EmitBundleAlignStart() = 0; + + /// EmitBundleAlignEnd - Guarantee that the next instruction or + /// bundle-locked group finishes at the end of a bundle. + virtual void EmitBundleAlignEnd() = 0; + /// @} + // @LOCALMOD-END + /// EmitFileDirective - Switch to a new logical file. This is used to /// implement the '.file "foo.c"' assembler directive. virtual void EmitFileDirective(StringRef Filename) = 0; diff --git a/include/llvm/Module.h b/include/llvm/Module.h index e6303ac775..13b56433dc 100644 --- a/include/llvm/Module.h +++ b/include/llvm/Module.h @@ -186,6 +186,22 @@ public: : Behavior(B), Key(K), Val(V) {} }; + /// @LOCALMOD-BEGIN + /// An enumeration for describing the module format + enum OutputFormat { + ObjectOutputFormat, + SharedOutputFormat, + ExecutableOutputFormat + }; + + /// A structure describing the symbols needed from an external file. + struct NeededRecord { + std::string DynFile; // Source file (soname) + std::vector<std::string> Symbols; // List of symbol names + // (with version suffix) + }; + /// @LOCALMOD-END + /// @} /// @name Member Variables /// @{ @@ -203,6 +219,9 @@ private: std::string ModuleID; ///< Human readable identifier for the module std::string TargetTriple; ///< Platform target triple Module compiled on std::string DataLayout; ///< Target data description + // @LOCALMOD-BEGIN + mutable std::string ModuleSOName; ///< Module SOName (for shared format) + // @LOCALMOD-END void *NamedMDSymTab; ///< NamedMDNode names. friend class Constant; @@ -234,6 +253,24 @@ public: /// @returns a string containing the target triple. const std::string &getTargetTriple() const { return TargetTriple; } + // @LOCALMOD-BEGIN + + /// Get the module format + /// @returns the module format + OutputFormat getOutputFormat() const; + + /// Get the SOName of this module. + /// @returns a string containing the module soname + const std::string &getSOName() const; + + /// Record the needed information for a global value. + /// This creates a needed record for DynFile, if one does not already exist. + void addNeededRecord(StringRef DynFile, GlobalValue *GV); + + // Fill NeededOut with all needed records present in the module. + void getNeededRecords(std::vector<NeededRecord> *NeededOut) const; + // @LOCALMOD-END + /// Get the target endian information. /// @returns Endianess - an enumeration for the endianess of the target Endianness getEndianness() const; @@ -263,6 +300,18 @@ public: /// Set the target triple. void setTargetTriple(StringRef T) { TargetTriple = T; } + /// @LOCALMOD-BEGIN + + /// Set the module format + void setOutputFormat(OutputFormat F); + + /// For modules with output format "shared", set the output soname. + void setSOName(StringRef Name); + + /// Wrap a global symbol. + void wrapSymbol(StringRef SymName); + /// @LOCALMOD-END + /// Set the module-scope inline assembly blocks. void setModuleInlineAsm(StringRef Asm) { GlobalScopeAsm = Asm; @@ -584,6 +633,11 @@ public: /// Dump the module to stderr (for debugging). void dump() const; + /// @LOCALMOD-BEGIN + /// Print the PNaCl metadata for the module. + void dumpMeta(raw_ostream &OS) const; + /// @LOCALMOD-END + /// This function causes all the subinstructions to "let go" of all references /// that they are maintaining. This allows one to 'delete' a whole class at /// a time, even though there may be circular references... first all diff --git a/include/llvm/Support/ELF.h b/include/llvm/Support/ELF.h index 13788832bd..dbd1091629 100644 --- a/include/llvm/Support/ELF.h +++ b/include/llvm/Support/ELF.h @@ -325,6 +325,7 @@ enum { ELFOSABI_C6000_ELFABI = 64, // Bare-metal TMS320C6000 ELFOSABI_C6000_LINUX = 65, // Linux TMS320C6000 ELFOSABI_ARM = 97, // ARM + ELFOSABI_NACL = 123, // Native Client // @LOCALMOD ELFOSABI_STANDALONE = 255 // Standalone (embedded) application }; diff --git a/include/llvm/Support/ValueHandle.h b/include/llvm/Support/ValueHandle.h index dbcf0fd11d..5e98fbd07a 100644 --- a/include/llvm/Support/ValueHandle.h +++ b/include/llvm/Support/ValueHandle.h @@ -104,6 +104,11 @@ protected: void setValPtrInt(unsigned K) { VP.setInt(K); } unsigned getValPtrInt() const { return VP.getInt(); } + // @LOCALMOD-BEGIN -- Hack for bug: + // http://code.google.com/p/nativeclient/issues/detail?id=2786 + void setKind(HandleBaseKind K) { PrevPair.setInt(K); } + // @LOCALMOD-END + static bool isValid(Value *V) { return V && V != DenseMapInfo<Value *>::getEmptyKey() && @@ -232,6 +237,15 @@ public: return getValPtr(); } + // @LOCALMOD-BEGIN -- Hack for bug: + // http://code.google.com/p/nativeclient/issues/detail?id=2786 + // This allows us to weaken the Asserting Value Handle in LexicalScopes.h, + // for Debug info only. + void make_weak() { + setKind(Weak); + } + // @LOCALMOD-END + ValueTy *operator->() const { return getValPtr(); } ValueTy &operator*() const { return *getValPtr(); } }; diff --git a/include/llvm/Support/support_macros.h b/include/llvm/Support/support_macros.h new file mode 100644 index 0000000000..83d62c722c --- /dev/null +++ b/include/llvm/Support/support_macros.h @@ -0,0 +1,25 @@ +// Define support macros for defining classes, etc. + +#ifndef LLVM_SUPPORT_SUPPORT_MACROS_H__ +#define LLVM_SUPPORT_SUPPORT_MACROS_H__ + +// Define macro, to use within a class declaration, to disallow constructor +// copy. Defines copy constructor declaration under the assumption that it +// is never defined. +#define DISALLOW_CLASS_COPY(class_name) \ + class_name(class_name& arg) // Do not implement + +// Define macro, to use within a class declaration, to disallow assignment. +// Defines assignment operation declaration under the assumption that it +// is never defined. +#define DISALLOW_CLASS_ASSIGN(class_name) \ + void operator=(class_name& arg) // Do not implement + +// Define macro to add copy and assignment declarations to a class file, +// for which no bodies will be defined, effectively disallowing these from +// being defined in the class. +#define DISALLOW_CLASS_COPY_AND_ASSIGN(class_name) \ + DISALLOW_CLASS_COPY(class_name); \ + DISALLOW_CLASS_ASSIGN(class_name) + +#endif // LLVM_SUPPORT_SUPPORT_MACROS_H__ diff --git a/include/llvm/Support/system_error.h b/include/llvm/Support/system_error.h index 0d164f688d..844013ed5d 100644 --- a/include/llvm/Support/system_error.h +++ b/include/llvm/Support/system_error.h @@ -597,7 +597,7 @@ enum _ { #else stream_timeout = ETIMEDOUT, #endif - text_file_busy = ETXTBSY, + text_file_busy = EINVAL, // @LOCALMOD timed_out = ETIMEDOUT, too_many_files_open_in_system = ENFILE, too_many_files_open = EMFILE, diff --git a/include/llvm/Target/Target.td b/include/llvm/Target/Target.td index a68eb8339d..ed3db69a4e 100644 --- a/include/llvm/Target/Target.td +++ b/include/llvm/Target/Target.td @@ -766,6 +766,40 @@ def LIFETIME_END : Instruction { let AsmString = "LIFETIME_END"; let neverHasSideEffects = 1; } +// @LOCALMOD-BEGIN +def BUNDLE_ALIGN_START : Instruction { + let OutOperandList = (outs); + let InOperandList = (ins); + let AsmString = ""; + let neverHasSideEffects = 1; + let isAsCheapAsAMove = 1; + let isNotDuplicable = 1; +} +def BUNDLE_ALIGN_END : Instruction { + let OutOperandList = (outs); + let InOperandList = (ins); + let AsmString = ""; + let neverHasSideEffects = 1; + let isAsCheapAsAMove = 1; + let isNotDuplicable = 1; +} +def BUNDLE_LOCK : Instruction { + let OutOperandList = (outs); + let InOperandList = (ins); + let AsmString = ""; + let neverHasSideEffects = 1; + let isAsCheapAsAMove = 1; + let isNotDuplicable = 1; +} +def BUNDLE_UNLOCK : Instruction { + let OutOperandList = (outs); + let InOperandList = (ins); + let AsmString = ""; + let neverHasSideEffects = 1; + let isAsCheapAsAMove = 1; + let isNotDuplicable = 1; +} +// @LOCALMOD-END } //===----------------------------------------------------------------------===// diff --git a/include/llvm/Target/TargetFrameLowering.h b/include/llvm/Target/TargetFrameLowering.h index d56db7b511..7df3bfa473 100644 --- a/include/llvm/Target/TargetFrameLowering.h +++ b/include/llvm/Target/TargetFrameLowering.h @@ -48,11 +48,19 @@ private: unsigned StackAlignment; unsigned TransientStackAlignment; int LocalAreaOffset; + + // @LOCALMOD-BEGIN + // TODO(pdox): Refactor this and upstream it, to get rid of the + // assumption that StackSlotSize == PointerSize. + unsigned StackSlotSize; + // @LOCALMOD-END public: - TargetFrameLowering(StackDirection D, unsigned StackAl, int LAO, - unsigned TransAl = 1) + TargetFrameLowering(StackDirection D, + unsigned StackAl, int LAO, + unsigned TransAl = 1, + unsigned SlotSize = 0) // @LOCALMOD : StackDir(D), StackAlignment(StackAl), TransientStackAlignment(TransAl), - LocalAreaOffset(LAO) {} + LocalAreaOffset(LAO), StackSlotSize(SlotSize) {} virtual ~TargetFrameLowering(); @@ -63,6 +71,11 @@ public: /// StackDirection getStackGrowthDirection() const { return StackDir; } + // @LOCALMOD-BEGIN + /// getStackSlotSize - Return the size of a stack slot + unsigned getStackSlotSize() const { return StackSlotSize; } + // @LOCALMOD-END + /// getStackAlignment - This method returns the number of bytes to which the /// stack pointer must be aligned on entry to a function. Typically, this /// is the largest alignment for any data object in the target. diff --git a/include/llvm/Target/TargetJITInfo.h b/include/llvm/Target/TargetJITInfo.h index 044afd9b73..c2bb376131 100644 --- a/include/llvm/Target/TargetJITInfo.h +++ b/include/llvm/Target/TargetJITInfo.h @@ -129,6 +129,25 @@ namespace llvm { /// separately allocated heap memory rather than in the same /// code memory allocated by JITCodeEmitter. virtual bool allocateSeparateGVMemory() const { return false; } + + // @LOCALMOD-START + // NaCl-specific, target-specific stuff + typedef struct { uint8_t *ins; int len; } HaltInstruction; + /// Get a sequence of NOPs of length len. Returns a pointer to a buffer + /// containing a val + virtual const uint8_t *getNopSequence(size_t len) const { return NULL; } + /// Get the length and definition of the halt/roadblock instruction + virtual const HaltInstruction *getHalt() const { return NULL; } + virtual int getBundleSize() const { return 0; } + virtual int32_t getJumpMask() const { return 0; } + + /// Relocations cannot happen in-place in NaCl because we can't write to + /// code. This function takes a pointer to where the code has been emitted, + /// before it is copied to the code region. The subsequent call to + /// relocate takes pointers to the target code location, but rewrites the + /// code in the relocation buffer rather than at the target + virtual void setRelocationBuffer(unsigned char * BufferBegin) {} + // @LOCALMOD-END protected: bool useGOT; }; diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index 9e46a40e29..a78ef58b88 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -116,6 +116,18 @@ public: // mask (ex: x86 blends). }; + // @LOCALMOD-START + // This needs to be kept in sync with + // native_client/src/untrusted/nacl/pnaclintrin.h. + enum PnaclTargetArchitecture { + PnaclTargetArchitectureInvalid = 0, + PnaclTargetArchitectureX86_32, + PnaclTargetArchitectureX86_64, + PnaclTargetArchitectureARM_32, + PnaclTargetArchitectureARM_32_Thumb + }; + // @LOCALMOD-END + static ISD::NodeType getExtendForContent(BooleanContent Content) { switch (Content) { case UndefinedBooleanContent: diff --git a/include/llvm/Target/TargetOpcodes.h b/include/llvm/Target/TargetOpcodes.h index 516e0706b8..2c9459974a 100644 --- a/include/llvm/Target/TargetOpcodes.h +++ b/include/llvm/Target/TargetOpcodes.h @@ -91,7 +91,14 @@ namespace TargetOpcode { /// Lifetime markers. LIFETIME_START = 15, - LIFETIME_END = 16 + LIFETIME_END = 16, + + // @LOCALMOD-BEGIN + BUNDLE_ALIGN_START = 14, + BUNDLE_ALIGN_END = 15, + BUNDLE_LOCK = 16, + BUNDLE_UNLOCK = 17 + // @LOCALMOD-END }; } // end namespace TargetOpcode } // end namespace llvm diff --git a/include/llvm/Target/TargetOptions.h b/include/llvm/Target/TargetOptions.h index 68ca567836..0a1b73e352 100644 --- a/include/llvm/Target/TargetOptions.h +++ b/include/llvm/Target/TargetOptions.h @@ -30,6 +30,12 @@ namespace llvm { }; } + // @LOCALMOD-BEGIN + /// TLSUseCall - This flag enables the use of a function call to get the + /// thread pointer for TLS accesses, instead of using inline code. + extern bool TLSUseCall; + // @LOCALMOD-END + namespace FPOpFusion { enum FPOpFusionMode { Fast, // Enable fusion of FP ops wherever it's profitable. diff --git a/include/llvm/Transforms/Scalar.h b/include/llvm/Transforms/Scalar.h index a5d8eed746..1ddca844c9 100644 --- a/include/llvm/Transforms/Scalar.h +++ b/include/llvm/Transforms/Scalar.h @@ -372,7 +372,7 @@ extern char &InstructionSimplifierID; // "block_weights" metadata. FunctionPass *createLowerExpectIntrinsicPass(); - +FunctionPass *createNaClCcRewritePass(const TargetLowering *TLI = 0); } // End llvm namespace #endif diff --git a/include/llvm/Value.h b/include/llvm/Value.h index 6560a420bf..41acc84415 100644 --- a/include/llvm/Value.h +++ b/include/llvm/Value.h @@ -105,6 +105,12 @@ public: /// Type *getType() const { return VTy; } + // @LOCALMOD-START + // Currently only used for function type update during + // the NaCl calling convention rewrite pass + void setType(Type* t) { VTy = t; } + // @LOCALMOD-END + /// All values hold a context through their type. LLVMContext &getContext() const; diff --git a/include/llvm/Wrap/BCHeaderField.h b/include/llvm/Wrap/BCHeaderField.h new file mode 100644 index 0000000000..40a3714c9f --- /dev/null +++ b/include/llvm/Wrap/BCHeaderField.h @@ -0,0 +1,106 @@ +/* Copyright 2012 The Native Client Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can + * be found in the LICENSE file. + */ + +#ifndef LLVM_WRAP_BCHEADERFIELD_H +#define LLVM_WRAP_BCHEADERFIELD_H +#include <limits> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +// Class representing a variable-size metadata field in the bitcode header. +// Also contains the list of known Tag IDs. +// Contains a pointer to the data but does not own the data, so it can be +// copied with the trivial copy constructor/assignment operator. + +// The serialized format has 2 fixed subfields (ID and length) and the +// variable-length data subfield +class BCHeaderField { + public: + typedef enum { + kInvalid = 0, + kBitcodeHash = 1, + kAndroidCompilerVersion = 0x4001, + kAndroidOptimizationLevel = 0x4002 + } Tag; + typedef uint16_t FixedSubfield; + + BCHeaderField(Tag ID, size_t len, uint8_t* data) : + ID_(ID), len_(len), data_(data) {} + size_t GetTotalSize() { + // Round up to 4 byte alignment + return (kTagLenSize + len_ + 3) & ~3; + } + + bool Write(uint8_t* buf, size_t buf_len) { + size_t fields_len = kTagLenSize + len_; + size_t pad_len = (4 - (fields_len & 3)) & 3; + // Ensure buffer is large enough and that length can be represented + // in 16 bits + if (buf_len < fields_len + pad_len || + len_ > std::numeric_limits<FixedSubfield>::max()) return false; + + WriteFixedSubfield(static_cast<FixedSubfield>(ID_), buf); + WriteFixedSubfield(static_cast<FixedSubfield>(len_), + buf + sizeof(FixedSubfield)); + memcpy(buf + kTagLenSize, data_, len_); + // Pad out to 4 byte alignment + if (pad_len) { + memset(buf + fields_len, 0, pad_len); + } + return true; + } + + bool Read(const uint8_t* buf, size_t buf_len) { + if (buf_len < kTagLenSize) return false; + FixedSubfield field; + ReadFixedSubfield(&field, buf); + ID_ = static_cast<Tag>(field); + ReadFixedSubfield(&field, buf + sizeof(FixedSubfield)); + len_ = static_cast<size_t>(field); + if (buf_len < kTagLenSize + len_) return false; + memcpy(data_, buf + kTagLenSize, len_); + return true; + } + + void Print() { + fprintf(stderr, "Field ID: %d, data length %d, total length %d\n", + ID_, static_cast<int>(len_), static_cast<int>(GetTotalSize())); + fprintf(stderr, "Data: "); + for (size_t i = 0; i < len_; i++) fprintf(stderr, "%02x", data_[i]); + fprintf(stderr, "\n"); + } + + // Get the data size from a serialized field to allow allocation + static size_t GetDataSizeFromSerialized(const uint8_t* buf) { + FixedSubfield len; + ReadFixedSubfield(&len, buf + sizeof(FixedSubfield)); + return len; + } + + Tag getID() const { + return ID_; + } + + size_t getLen() const { + return len_; + } + + private: + // Combined size of the fixed subfields + const static size_t kTagLenSize = 2 * sizeof(FixedSubfield); + static void WriteFixedSubfield(FixedSubfield value, uint8_t* buf) { + buf[0] = value & 0xFF; + buf[1] = (value >> 8) & 0xFF; + } + static void ReadFixedSubfield(FixedSubfield* value, const uint8_t* buf) { + *value = buf[0] | buf[1] << 8; + } + Tag ID_; + size_t len_; + uint8_t *data_; +}; + +#endif diff --git a/include/llvm/Wrap/bitcode_wrapperer.h b/include/llvm/Wrap/bitcode_wrapperer.h new file mode 100644 index 0000000000..89f2a4cbcc --- /dev/null +++ b/include/llvm/Wrap/bitcode_wrapperer.h @@ -0,0 +1,192 @@ +/* Copyright 2012 The Native Client Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can + * be found in the LICENSE file. + */ + +// Define utility class to wrap/unwrap bitcode files. Does wrapping/unwrapping +// in such a way that the wrappered bitcode file is still a bitcode file. + +#ifndef LLVM_WRAP_BITCODE_WRAPPERER_H__ +#define LLVM_WRAP_BITCODE_WRAPPERER_H__ + +#include <stdint.h> +#include <stddef.h> +#include <vector> + +#include "llvm/Support/support_macros.h" +#include "llvm/Wrap/BCHeaderField.h" +#include "llvm/Wrap/wrapper_input.h" +#include "llvm/Wrap/wrapper_output.h" + +// The bitcode wrapper header is the following 7 fixed 4-byte fields: +// 1) 0B17C0DE - The magic number expected by llvm for wrapped bitcodes +// 2) Version # 0 - The current version of wrapped bitcode files +// 3) (raw) bitcode offset +// 4) (raw) bitcode size +// 5) Android header version +// 6) Android target API +// 7) PNaCl Bitcode version +// plus 0 or more variable-length fields (consisting of ID, length, data) + +// Initial buffer size. It is expanded if needed to hold large variable-size +// fields. +static const size_t kBitcodeWrappererBufferSize = 1024; + +// Support class for outputting a wrapped bitcode file from a raw bitcode +// file (and optionally additional header fields), or for outputting a raw +// bitcode file from a wrapped one. +class BitcodeWrapperer { + public: + // Create a bitcode wrapperer using the following + // input and output files. + BitcodeWrapperer(WrapperInput* infile, WrapperOutput* outfile); + + // Returns true if the input file begins with a bitcode + // wrapper magic number. As a side effect, _wrapper_ fields are set. + bool IsInputBitcodeWrapper(); + + // Returns true if the input file begins with a bitcode + // file magic number. + bool IsInputBitcodeFile(); + + // Add a variable-length field to the header. The caller is responsible + // for freeing the data pointed to by the BCHeaderField. + void AddHeaderField(BCHeaderField* field); + + // Generate a wrapped bitcode file from the input bitcode file + // and the current header data. Return true on success. + bool GenerateWrappedBitcodeFile(); + + // Unwrap the wrapped bitcode file, to the corresponding + // outfile. Return true on success. + bool GenerateRawBitcodeFile(); + + // Print current wrapper header fields to stderr for debugging. + void PrintWrapperHeader(); + + ~BitcodeWrapperer(); + + private: + DISALLOW_CLASS_COPY_AND_ASSIGN(BitcodeWrapperer); + + // Refills the buffer with more bytes. Does this in a way + // such that it is maximally filled. + void FillBuffer(); + + // Returns the number of bytes in infile. + off_t GetInFileSize() { + if (infile_ != NULL) { + return infile_->Size(); + } else { + return 0; + } + } + + // Returns the offset of bitcode (i.e. the size of the wrapper header) + // if the output file were to be written now. + size_t BitcodeOffset(); + + // Returns true if we can read a word. If necessary, fills the buffer + // with enough characters so that there are at least a 32-bit value + // in the buffer. Returns false if there isn't a 32-bit value + // to read from the input file. + bool CanReadWord(); + + // Read a (32-bit) word from the input. Return true + // if able to read the word. + bool ReadWord(uint32_t& word); + + // Write a (32-bit) word to the output. Return true if successful + bool WriteWord(uint32_t word); + + // Write all variable-sized header fields to the output. Return true + // if successful. + bool WriteVariableFields(); + + // Parse the bitcode wrapper header in the infile, if any. Return true + // if successful. + bool ParseWrapperHeader(); + + // Returns the i-th character in front of the cursor in the buffer. + uint8_t BufferLookahead(int i) { return buffer_[cursor_ + i]; } + + // Returns how many unread bytes are in the buffer. + size_t GetBufferUnreadBytes() { return buffer_size_ - cursor_; } + + + // Backs up the read cursor to the beginning of the input buffer. + void ResetCursor() { + cursor_ = 0; + } + + // Generates the header sequence for the wrapped bitcode being + // generated. + bool WriteBitcodeWrapperHeader(); + + // Copies size bytes of infile to outfile, using the buffer. + bool BufferCopyInToOut(uint32_t size); + + // Discards the old infile and replaces it with the given file. + void ReplaceInFile(WrapperInput* new_infile); + + // Discards the old outfile and replaces it with the given file. + void ReplaceOutFile(WrapperOutput* new_outfile); + + // Moves to the given position in the input file. Returns false + // if unsuccessful. + bool Seek(uint32_t pos); + + // Clear the buffer of all contents. + void ClearBuffer(); + + // The input file being processed. Can be either + // a bitcode file, a wrappered bitcode file, or a secondary + // file to be wrapped. + WrapperInput* infile_; + + // The output file being generated. Can be either + // a bitcode file, a wrappered bitcode file, or a secondary + // unwrapped file. + WrapperOutput* outfile_; + + // A buffer of bytes read from the input file. + std::vector<uint8_t> buffer_; + + // The number of bytes that were read from the input file + // into the buffer. + size_t buffer_size_; + + // The index to the current read point within the buffer. + size_t cursor_; + + // True when eof of input is reached. + bool infile_at_eof_; + + // The 32-bit value defining the offset of the raw bitcode in the input file. + uint32_t infile_bc_offset_; + + // The 32-bit value defining the generated offset of the wrapped bitcode. + // This value changes as new fields are added with AddHeaderField + uint32_t wrapper_bc_offset_; + + // The 32-bit value defining the size of the raw wrapped bitcode. + uint32_t wrapper_bc_size_; + + // Android header version and target API + uint32_t android_header_version_; + uint32_t android_target_api_; + + // PNaCl bitcode version + uint32_t pnacl_bc_version_; + + // Vector of variable header fields + std::vector<BCHeaderField> header_fields_; + // If any bufferdata from header fields is owned, it is stored here and + // freed on destruction. + std::vector<uint8_t*> variable_field_data_; + + // True if there was an error condition (e.g. the file is not bitcode) + bool error_; +}; + +#endif // LLVM_WRAP_BITCODE_WRAPPERER_H__ diff --git a/include/llvm/Wrap/file_wrapper_input.h b/include/llvm/Wrap/file_wrapper_input.h new file mode 100644 index 0000000000..9f3de004c4 --- /dev/null +++ b/include/llvm/Wrap/file_wrapper_input.h @@ -0,0 +1,48 @@ +/* Copyright 2012 The Native Client Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can + * be found in the LICENSE file. + */ + +// Defines utility allowing files for bitcode input wrapping. + +#ifndef FILE_WRAPPER_INPUT_H__ +#define FILE_WRAPPER_INPUT_H__ + +#include "llvm/Support/support_macros.h" +#include "llvm/Wrap/wrapper_input.h" + +#include <stdio.h> +#include <string> + +// Define a class to wrap named files. +class FileWrapperInput : public WrapperInput { + public: + FileWrapperInput(const std::string& name); + ~FileWrapperInput(); + // Tries to read the requested number of bytes into the buffer. Returns the + // actual number of bytes read. + virtual size_t Read(uint8_t* buffer, size_t wanted); + // Returns true if at end of file. Note: May return false + // until Read is called, and returns 0. + virtual bool AtEof(); + // Returns the size of the file (in bytes). + virtual off_t Size(); + // Moves to the given offset within the file. Returns + // false if unable to move to that position. + virtual bool Seek(uint32_t pos); + private: + // The name of the file. + std::string _name; + // True once eof has been encountered. + bool _at_eof; + // True if size has been computed. + bool _size_found; + // The size of the file. + off_t _size; + // The corresponding (opened) file. + FILE* _file; + private: + DISALLOW_CLASS_COPY_AND_ASSIGN(FileWrapperInput); +}; + +#endif // FILE_WRAPPER_INPUT_H__ diff --git a/include/llvm/Wrap/file_wrapper_output.h b/include/llvm/Wrap/file_wrapper_output.h new file mode 100644 index 0000000000..714bd36a75 --- /dev/null +++ b/include/llvm/Wrap/file_wrapper_output.h @@ -0,0 +1,34 @@ +/* Copyright 2012 The Native Client Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can + * be found in the LICENSE file. + */ + +// Defines utility allowing files for bitcode output wrapping. + +#ifndef FILE_WRAPPER_OUTPUT_H__ +#define FILE_WRAPPER_OUTPUT_H__ + +#include "llvm/Support/support_macros.h" +#include "llvm/Wrap/wrapper_output.h" +#include <stdio.h> +#include <string> + +// Define a class to wrap named files. */ +class FileWrapperOutput : public WrapperOutput { + public: + FileWrapperOutput(const std::string& name); + ~FileWrapperOutput(); + // Writes a single byte, returning false if unable to write. + virtual bool Write(uint8_t byte); + // Writes the specified number of bytes in the buffer to + // output. Returns false if unable to write. + virtual bool Write(const uint8_t* buffer, size_t buffer_size); + private: + // The name of the file + std::string _name; + // The corresponding (opened) file. + FILE* _file; + private: + DISALLOW_CLASS_COPY_AND_ASSIGN(FileWrapperOutput); +}; +#endif // FILE_WRAPPER_OUTPUT_H__ diff --git a/include/llvm/Wrap/wrapper_input.h b/include/llvm/Wrap/wrapper_input.h new file mode 100644 index 0000000000..cde918083a --- /dev/null +++ b/include/llvm/Wrap/wrapper_input.h @@ -0,0 +1,38 @@ +/* Copyright 2012 The Native Client Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can + * be found in the LICENSE file. + */ + +// Define a generic interface to a file/memory region that contains +// a bitcode file, a wrapped bitcode file, or a data file to wrap. + +#ifndef LLVM_WRAP_WRAPPER_INPUT_H__ +#define LLVM_WRAP_WRAPPER_INPUT_H__ + +#include <stdint.h> +#include <sys/types.h> + +#include "llvm/Support/support_macros.h" + +// The following is a generic interface to a file/memory region that contains +// a bitcode file, a wrapped bitcode file, or data file to wrap. +class WrapperInput { + public: + WrapperInput() {} + virtual ~WrapperInput() {} + // Tries to read the requested number of bytes into the buffer. Returns the + // actual number of bytes read. + virtual size_t Read(uint8_t* buffer, size_t wanted) = 0; + // Returns true if at end of input. Note: May return false until + // Read is called, and returns 0. + virtual bool AtEof() = 0; + // Returns the size of the input (in bytes). + virtual off_t Size() = 0; + // Moves to the given offset within the input region. Returns false + // if unable to move to that position. + virtual bool Seek(uint32_t pos) = 0; + private: + DISALLOW_CLASS_COPY_AND_ASSIGN(WrapperInput); +}; + +#endif // LLVM_WRAP_WRAPPER_INPUT_H__ diff --git a/include/llvm/Wrap/wrapper_output.h b/include/llvm/Wrap/wrapper_output.h new file mode 100644 index 0000000000..7045705991 --- /dev/null +++ b/include/llvm/Wrap/wrapper_output.h @@ -0,0 +1,34 @@ +/* Copyright 2012 The Native Client Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can + * be found in the LICENSE file. + */ + +// Defines a generic interface to a file/memory region that +// contains a generated wrapped bitcode file, bitcode file, +// or data file. + +#ifndef LLVM_WRAP_WRAPPER_OUTPUT_H__ +#define LLVM_WRAP_WRAPPER_OUTPUT_H__ + +#include <stdint.h> +#include <stddef.h> + +#include "llvm/Support/support_macros.h" + +// The following is a generic interface to a file/memory region +// that contains a generated bitcode file, wrapped bitcode file, +// or a data file. +class WrapperOutput { + public: + WrapperOutput() {} + virtual ~WrapperOutput() {} + // Writes a single byte, returning false if unable to write. + virtual bool Write(uint8_t byte) = 0; + // Writes the specified number of bytes in the buffer to + // output. Returns false if unable to write. + virtual bool Write(const uint8_t* buffer, size_t buffer_size); + private: + DISALLOW_CLASS_COPY_AND_ASSIGN(WrapperOutput); +}; + +#endif // LLVM_WRAP_WRAPPER_OUTPUT_H__ |