| //===------------- Convert.cpp - Converting gimple to LLVM IR -------------===// |
| // |
| // Copyright (C) 2005 to 2013 Chris Lattner, Duncan Sands et al. |
| // |
| // This file is part of DragonEgg. |
| // |
| // DragonEgg is free software; you can redistribute it and/or modify it under |
| // the terms of the GNU General Public License as published by the Free Software |
| // Foundation; either version 2, or (at your option) any later version. |
| // |
| // DragonEgg is distributed in the hope that it will be useful, but WITHOUT ANY |
| // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR |
| // A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
| // |
| // You should have received a copy of the GNU General Public License along with |
| // DragonEgg; see the file COPYING. If not, write to the Free Software |
| // Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. |
| // |
| //===----------------------------------------------------------------------===// |
| // This is the code that converts GCC AST nodes into LLVM code. |
| //===----------------------------------------------------------------------===// |
| |
| // Plugin headers |
| #include "dragonegg/ABI.h" |
| #include "dragonegg/Aliasing.h" |
| #include "dragonegg/ConstantConversion.h" |
| #include "dragonegg/Debug.h" |
| #include "dragonegg/TypeConversion.h" |
| |
| // LLVM headers |
| #include "llvm/ADT/Statistic.h" |
| #include "llvm/ADT/StringExtras.h" |
| #include "llvm/IR/MDBuilder.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/Support/CFG.h" |
| #include "llvm/Support/Debug.h" |
| #include "llvm/Target/TargetLowering.h" |
| |
| // System headers |
| #include <gmp.h> |
| |
| // GCC headers |
| #include "auto-host.h" |
| #ifndef ENABLE_BUILD_WITH_CXX |
| #include <cstring> // Otherwise included by system.h with C linkage. |
| extern "C" { |
| #endif |
| #include "config.h" |
| // Stop GCC declaring 'getopt' as it can clash with the system's declaration. |
| #undef HAVE_DECL_GETOPT |
| #include "system.h" |
| #include "coretypes.h" |
| #include "tm.h" |
| #include "tree.h" |
| |
| #include "diagnostic.h" |
| #include "except.h" |
| #include "flags.h" |
| #if (GCC_MINOR > 6) |
| #include "gimple-pretty-print.h" |
| #endif |
| #include "langhooks.h" |
| #include "output.h" |
| #include "rtl.h" |
| #include "target.h" // For targetm. |
| #include "tm_p.h" |
| #include "toplev.h" |
| #include "tree-flow.h" |
| #include "tree-pass.h" |
| |
| using namespace llvm; |
| |
| #if (GCC_MINOR < 6) |
| extern enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER]; |
| #else |
| // TODO: Submit a GCC patch to install "regs.h" as a plugin header. |
| struct target_regs { |
| unsigned char x_hard_regno_nregs[FIRST_PSEUDO_REGISTER][MAX_MACHINE_MODE]; |
| enum machine_mode x_reg_raw_mode[FIRST_PSEUDO_REGISTER]; |
| }; |
| |
| extern struct target_regs default_target_regs; |
| |
| #define reg_raw_mode (default_target_regs.x_reg_raw_mode) |
| #endif |
| |
| #if (GCC_MINOR == 6) |
| extern void debug_gimple_stmt(union gimple_statement_d *); |
| #endif |
| |
| #ifndef ENABLE_BUILD_WITH_CXX |
| } // extern "C" |
| #endif |
| |
| // Trees header. |
| #include "dragonegg/Trees.h" |
| |
| static LLVMContext &Context = getGlobalContext(); |
| |
| STATISTIC(NumBasicBlocks, "Number of basic blocks converted"); |
| STATISTIC(NumStatements, "Number of gimple statements converted"); |
| |
| /// getPointerAlignment - Return the alignment in bytes of exp, a pointer valued |
| /// expression, or 1 if the alignment is not known. |
| static unsigned int getPointerAlignment(tree exp) { |
| assert(isa<ACCESS_TYPE>(TREE_TYPE(exp)) && "Expected a pointer type!"); |
| unsigned int align = |
| #if (GCC_MINOR < 7) |
| get_pointer_alignment(exp, BIGGEST_ALIGNMENT); |
| #else |
| get_pointer_alignment(exp); |
| #endif |
| return align >= 8 ? align / 8 : 1; |
| } |
| |
| /// getSSAPlaceholder - A fake value associated with an SSA name when the name |
| /// is used before being defined (this can occur because basic blocks are not |
| /// output in dominator order). Replaced with the correct value when the SSA |
| /// name's definition is encountered. |
| static Value *GetSSAPlaceholder(Type *Ty) { |
| // Cannot use a constant, since there is no way to distinguish a fake value |
| // from a real value. So use an instruction with no parent. This needs to |
| // be an instruction that can return a struct type, since the SSA name might |
| // be a complex number. It could be a PHINode, except that the GCC phi node |
| // conversion logic also constructs phi nodes with no parent. A SelectInst |
| // would work, but a LoadInst seemed neater. |
| return new LoadInst(UndefValue::get(Ty->getPointerTo()), NULL); |
| } |
| |
| /// isSSAPlaceholder - Whether this is a fake value being used as a placeholder |
| /// for the definition of an SSA name. |
| static bool isSSAPlaceholder(Value *V) { |
| LoadInst *LI = llvm::dyn_cast<LoadInst>(V); |
| return LI && !LI->getParent(); |
| } |
| |
| /// NameValue - Try to name the given value after the given GCC tree node. If |
| /// the GCC tree node has no sensible name then it does nothing. If the value |
| /// already has a name then it is not changed. |
| static void NameValue(Value *V, tree t) { |
| if (!V->hasName()) { |
| const std::string &Name = getDescriptiveName(t); |
| if (!Name.empty()) |
| V->setName(Name); |
| } |
| } |
| |
| /// SelectFPName - Helper for choosing a name depending on whether a floating |
| /// point type is float, double or long double. Returns an empty string for |
| /// other types, such as the x86 128 bit floating point type. |
| static StringRef SelectFPName(tree type, StringRef FloatName, |
| StringRef DoubleName, StringRef LongDoubleName) { |
| assert(isa<REAL_TYPE>(type) && "Expected a floating point type!"); |
| if (TYPE_MODE(type) == TYPE_MODE(float_type_node)) |
| return FloatName; |
| if (TYPE_MODE(type) == TYPE_MODE(double_type_node)) |
| return DoubleName; |
| if (TYPE_MODE(type) == TYPE_MODE(long_double_type_node)) |
| return LongDoubleName; |
| return StringRef(); |
| } |
| |
| /// DisplaceLocationByUnits - Move a memory location by a fixed number of units. |
| /// This uses an "inbounds" getelementptr, so the displacement should remain |
| /// inside the original object. |
| MemRef |
| DisplaceLocationByUnits(MemRef Loc, int32_t Offset, LLVMBuilder &Builder) { |
| // Convert to a byte pointer and displace by the offset. |
| unsigned AddrSpace = Loc.Ptr->getType()->getPointerAddressSpace(); |
| Type *UnitPtrTy = GetUnitPointerType(Context, AddrSpace); |
| Value *Ptr = Builder.CreateBitCast(Loc.Ptr, UnitPtrTy); |
| Ptr = Builder.CreateConstInBoundsGEP1_32(Ptr, Offset, |
| flag_verbose_asm ? "dsplc" : ""); |
| Ptr = Builder.CreateBitCast(Ptr, Loc.Ptr->getType()); |
| uint32_t Align = MinAlign(Loc.getAlignment(), Offset); |
| return MemRef(Ptr, Align, Loc.Volatile); |
| } |
| |
| /// LoadFromLocation - Load a value of the given type from a memory location. |
| static LoadInst * |
| LoadFromLocation(MemRef Loc, Type *Ty, MDNode *AliasTag, LLVMBuilder &Builder) { |
| unsigned AddrSpace = Loc.Ptr->getType()->getPointerAddressSpace(); |
| Value *Ptr = Builder.CreateBitCast(Loc.Ptr, Ty->getPointerTo(AddrSpace)); |
| LoadInst *LI = |
| Builder.CreateAlignedLoad(Ptr, Loc.getAlignment(), Loc.Volatile); |
| if (AliasTag) |
| LI->setMetadata(LLVMContext::MD_tbaa, AliasTag); |
| return LI; |
| } |
| |
| /// StoreToLocation - Store a value to the given memory location. |
| static StoreInst * |
| StoreToLocation(Value *V, MemRef Loc, MDNode *AliasTag, LLVMBuilder &Builder) { |
| Type *Ty = V->getType(); |
| unsigned AddrSpace = Loc.Ptr->getType()->getPointerAddressSpace(); |
| Value *Ptr = Builder.CreateBitCast(Loc.Ptr, Ty->getPointerTo(AddrSpace)); |
| StoreInst *SI = |
| Builder.CreateAlignedStore(V, Ptr, Loc.getAlignment(), Loc.Volatile); |
| if (AliasTag) |
| SI->setMetadata(LLVMContext::MD_tbaa, AliasTag); |
| return SI; |
| } |
| |
| /// Mem2Reg - Convert a value of in-memory type (that given by ConvertType) |
| /// to in-register type (that given by getRegType). TODO: Eliminate these |
| /// methods: "memory" values should never be held in registers. Currently |
| /// this is mainly used for marshalling function parameters and return values, |
| /// but that should be completely independent of the reg vs mem value logic. |
| static Value *Mem2Reg(Value *V, tree type, LLVMBuilder &Builder) { |
| Type *MemTy = V->getType(); |
| Type *RegTy = getRegType(type); |
| assert(MemTy == ConvertType(type) && "Not of memory type!"); |
| |
| if (MemTy == RegTy) |
| return V; |
| |
| if (RegTy->isIntegerTy()) { |
| assert(MemTy->isIntegerTy() && "Type mismatch!"); |
| return Builder.CreateIntCast(V, RegTy, /*isSigned*/ !TYPE_UNSIGNED(type)); |
| } |
| |
| if (RegTy->isPointerTy()) { |
| assert(MemTy->isPointerTy() && "Type mismatch!"); |
| return Builder.CreateBitCast(V, RegTy); |
| } |
| |
| if (RegTy->isStructTy()) { |
| assert(isa<COMPLEX_TYPE>(type) && "Expected a complex type!"); |
| assert(MemTy->isStructTy() && "Type mismatch!"); |
| Value *RealPart = Builder.CreateExtractValue(V, 0); |
| Value *ImagPart = Builder.CreateExtractValue(V, 1); |
| RealPart = Mem2Reg(RealPart, TREE_TYPE(type), Builder); |
| ImagPart = Mem2Reg(ImagPart, TREE_TYPE(type), Builder); |
| V = UndefValue::get(RegTy); |
| V = Builder.CreateInsertValue(V, RealPart, 0); |
| V = Builder.CreateInsertValue(V, ImagPart, 1); |
| return V; |
| } |
| |
| if (RegTy->isVectorTy()) { |
| assert(isa<VECTOR_TYPE>(type) && "Expected a vector type!"); |
| assert(MemTy->isVectorTy() && "Type mismatch!"); |
| Value *Res = UndefValue::get(RegTy); |
| unsigned NumElts = (unsigned) TYPE_VECTOR_SUBPARTS(type); |
| for (unsigned i = 0; i != NumElts; ++i) { |
| Value *Idx = Builder.getInt32(i); |
| Value *Val = Builder.CreateExtractElement(V, Idx); |
| Val = Mem2Reg(Val, TREE_TYPE(type), Builder); |
| Res = Builder.CreateInsertElement(Res, Val, Idx); |
| } |
| return Res; |
| } |
| |
| debug_tree(type); |
| llvm_unreachable("Don't know how to turn this into a register!"); |
| } |
| |
| /// Reg2Mem - Convert a value of in-register type (that given by getRegType) |
| /// to in-memory type (that given by ConvertType). TODO: Eliminate this |
| /// method: "memory" values should never be held in registers. Currently |
| /// this is mainly used for marshalling function parameters and return values, |
| /// but that should be completely independent of the reg vs mem value logic. |
| static Value *Reg2Mem(Value *V, tree type, LLVMBuilder &Builder) { |
| Type *RegTy = V->getType(); |
| Type *MemTy = ConvertType(type); |
| assert(RegTy == getRegType(type) && "Not of register type!"); |
| |
| if (RegTy == MemTy) |
| return V; |
| |
| if (MemTy->isIntegerTy()) { |
| assert(RegTy->isIntegerTy() && "Type mismatch!"); |
| return Builder.CreateIntCast(V, MemTy, /*isSigned*/ !TYPE_UNSIGNED(type)); |
| } |
| |
| if (MemTy->isPointerTy()) { |
| assert(RegTy->isPointerTy() && "Type mismatch!"); |
| return Builder.CreateBitCast(V, MemTy); |
| } |
| |
| if (MemTy->isStructTy()) { |
| assert(isa<COMPLEX_TYPE>(type) && "Expected a complex type!"); |
| assert(RegTy->isStructTy() && "Type mismatch!"); |
| Value *RealPart = Builder.CreateExtractValue(V, 0); |
| Value *ImagPart = Builder.CreateExtractValue(V, 1); |
| RealPart = Reg2Mem(RealPart, TREE_TYPE(type), Builder); |
| ImagPart = Reg2Mem(ImagPart, TREE_TYPE(type), Builder); |
| Value *Z = UndefValue::get(MemTy); |
| Z = Builder.CreateInsertValue(Z, RealPart, 0); |
| Z = Builder.CreateInsertValue(Z, ImagPart, 1); |
| return Z; |
| } |
| |
| if (MemTy->isVectorTy()) { |
| assert(isa<VECTOR_TYPE>(type) && "Expected a vector type!"); |
| assert(RegTy->isVectorTy() && "Type mismatch!"); |
| Value *Res = UndefValue::get(MemTy); |
| unsigned NumElts = (unsigned) TYPE_VECTOR_SUBPARTS(type); |
| for (unsigned i = 0; i != NumElts; ++i) { |
| Value *Idx = Builder.getInt32(i); |
| Value *Val = Builder.CreateExtractElement(V, Idx); |
| Val = Reg2Mem(Val, TREE_TYPE(type), Builder); |
| Res = Builder.CreateInsertElement(Res, Val, Idx); |
| } |
| return Res; |
| } |
| |
| debug_tree(type); |
| llvm_unreachable("Don't know how to turn this into memory!"); |
| } |
| |
| /// describeTypeRange - Return metadata describing the set of possible values |
| /// that an in-memory variable of the given GCC type can take on. |
| static MDNode *describeTypeRange(tree type) { |
| if (!isa<INTEGRAL_TYPE>(type)) |
| return 0; // Only discrete types have ranges. |
| |
| // The range of possible values is TYPE_MIN_VALUE .. TYPE_MAX_VALUE. |
| tree min = TYPE_MIN_VALUE(type); |
| assert(min && isa<INTEGER_CST>(min) && "Min not a constant!"); |
| tree max = TYPE_MAX_VALUE(type); |
| assert(max && isa<INTEGER_CST>(max) && "Max not a constant!"); |
| |
| unsigned BitWidth = GET_MODE_BITSIZE(TYPE_MODE(type)); |
| |
| APInt Lo = getAPIntValue(min, BitWidth); |
| APInt Hi = getAPIntValue(max, BitWidth); |
| |
| // Unlike GCC's, LLVM ranges do not include the upper end point. |
| ++Hi; |
| |
| MDBuilder MDHelper(Context); |
| return MDHelper.createRange(Lo, Hi); |
| } |
| |
| /// isDirectMemoryAccessSafe - Whether directly storing/loading a value of the |
| /// given register type generates the correct in-memory representation for the |
| /// type. Eg, if a 32 bit wide integer type has only one bit of precision then |
| /// the register type is i1 and the in-memory type i32. Storing an i1 directly |
| /// to memory would not properly set up all 32 in-memory bits, thus this method |
| /// would return false. |
| static bool isDirectMemoryAccessSafe(Type *RegTy, tree type) { |
| assert(RegTy == getRegType(type) && "Wrong register type!"); |
| |
| switch (TREE_CODE(type)) { |
| default: |
| debug_tree(type); |
| llvm_unreachable("Unknown register type!"); |
| |
| case BOOLEAN_TYPE: |
| case ENUMERAL_TYPE: |
| case INTEGER_TYPE: |
| assert(RegTy->isIntegerTy() && "Expected an integer type!"); |
| return RegTy->getIntegerBitWidth() == GET_MODE_BITSIZE(TYPE_MODE(type)); |
| |
| case COMPLEX_TYPE: |
| case VECTOR_TYPE: { |
| assert((!isa<COMPLEX_TYPE>(type) || RegTy->isStructTy()) && |
| "Expected a struct type!"); |
| assert((!isa<VECTOR_TYPE>(type) || RegTy->isVectorTy()) && |
| "Expected a vector type!"); |
| tree elt_type = main_type(type); |
| Type *EltRegTy = getRegType(elt_type); |
| // Check that fields are safe to access directly. |
| if (!isDirectMemoryAccessSafe(EltRegTy, elt_type)) |
| return false; |
| // Check that the field positions agree with GCC. |
| unsigned StrideBits = GET_MODE_BITSIZE(TYPE_MODE(elt_type)); |
| return getDataLayout().getTypeAllocSizeInBits(EltRegTy) == StrideBits; |
| } |
| |
| case OFFSET_TYPE: |
| assert(RegTy->isIntegerTy() && "Expected an integer type!"); |
| return true; |
| |
| #if (GCC_MINOR > 5) |
| case NULLPTR_TYPE: |
| #endif |
| case POINTER_TYPE: |
| case REFERENCE_TYPE: |
| assert(RegTy->isPointerTy() && "Expected a pointer type!"); |
| return true; |
| |
| case REAL_TYPE: |
| assert(RegTy->isFloatingPointTy() && "Expected a floating point type!"); |
| // NOTE: This might be wrong for floats with precision less than their alloc |
| // size on big-endian machines. |
| return true; |
| } |
| } |
| |
| /// LoadRegisterFromMemory - Loads a value of the given scalar GCC type from |
| /// the memory location pointed to by Loc. Takes care of adjusting for any |
| /// differences between in-memory and in-register types (the returned value |
| /// is of in-register type, as returned by getRegType). |
| static Value *LoadRegisterFromMemory(MemRef Loc, tree type, MDNode *AliasTag, |
| LLVMBuilder &Builder) { |
| // NOTE: Needs to be kept in sync with getRegType. |
| Type *RegTy = getRegType(type); |
| |
| // If loading the register type directly out of memory gives the right result, |
| // then just do that. |
| if (isDirectMemoryAccessSafe(RegTy, type)) { |
| LoadInst *LI = LoadFromLocation(Loc, RegTy, AliasTag, Builder); |
| MDNode *Range = describeTypeRange(type); |
| if (Range) |
| LI->setMetadata(LLVMContext::MD_range, Range); |
| return LI; |
| } |
| |
| // There is a discrepancy between the in-register type and the in-memory type. |
| switch (TREE_CODE(type)) { |
| default: |
| debug_tree(type); |
| llvm_unreachable("Unexpected type mismatch!"); |
| |
| case BOOLEAN_TYPE: |
| case ENUMERAL_TYPE: |
| case INTEGER_TYPE: { |
| // For integral types, load an integer with size equal to the mode size, |
| // then truncate down to the precision. For example, when extracting a bool |
| // this probably first loads out an i8 or i32 which is then truncated to i1. |
| // This roundabout approach means we get the right result on both little and |
| // big endian machines. |
| unsigned Size = GET_MODE_BITSIZE(TYPE_MODE(type)); |
| Type *MemTy = IntegerType::get(Context, Size); |
| LoadInst *LI = LoadFromLocation(Loc, MemTy, AliasTag, Builder); |
| MDNode *Range = describeTypeRange(type); |
| if (Range) |
| LI->setMetadata(LLVMContext::MD_range, Range); |
| return Builder.CreateTruncOrBitCast(LI, RegTy); |
| } |
| |
| case COMPLEX_TYPE: { |
| // Load the complex number component by component. |
| tree elt_type = main_type(type); |
| unsigned Stride = GET_MODE_SIZE(TYPE_MODE(elt_type)); |
| Value *RealPart = LoadRegisterFromMemory(Loc, elt_type, AliasTag, Builder); |
| Loc = DisplaceLocationByUnits(Loc, Stride, Builder); |
| Value *ImagPart = LoadRegisterFromMemory(Loc, elt_type, AliasTag, Builder); |
| Value *Res = UndefValue::get(RegTy); |
| Res = Builder.CreateInsertValue(Res, RealPart, 0); |
| Res = Builder.CreateInsertValue(Res, ImagPart, 1); |
| return Res; |
| } |
| |
| case VECTOR_TYPE: { |
| tree elt_type = main_type(type); |
| Type *EltRegTy = getRegType(elt_type); |
| unsigned NumElts = TYPE_VECTOR_SUBPARTS(type); |
| unsigned Size = GET_MODE_BITSIZE(TYPE_MODE(elt_type)); |
| // If, say, the register type is a vector of i1 but memory is laid out as a |
| // vector of i32 then load an i32 vector out and truncate to a vector of i1. |
| if (EltRegTy->isIntegerTy() && EltRegTy->getIntegerBitWidth() != Size) { |
| // See if changing the element type to an integer with size equal to the |
| // mode size gives a vector type that corresponds to the in-memory layout. |
| Type *MemTy = IntegerType::get(Context, Size); |
| if (getDataLayout().getTypeAllocSizeInBits(MemTy) == Size) { |
| // It does! Load out the memory as a vector of that type then truncate |
| // to the register size. |
| Type *MemVecTy = VectorType::get(MemTy, NumElts); |
| LoadInst *LI = LoadFromLocation(Loc, MemVecTy, AliasTag, Builder); |
| return Builder.CreateTruncOrBitCast(LI, RegTy); |
| } |
| } |
| // Otherwise, load the vector component by component. |
| Value *Res = UndefValue::get(RegTy); |
| unsigned Stride = GET_MODE_SIZE(TYPE_MODE(elt_type)); |
| for (unsigned i = 0; i != NumElts; ++i) { |
| Value *Idx = Builder.getInt32(i); |
| Value *Elt = LoadRegisterFromMemory(Loc, elt_type, AliasTag, Builder); |
| Res = Builder.CreateInsertElement(Res, Elt, Idx); |
| if (i + 1 != NumElts) |
| Loc = DisplaceLocationByUnits(Loc, Stride, Builder); |
| } |
| return Res; |
| } |
| } |
| } |
| |
| /// StoreRegisterToMemory - Stores the given value to the memory pointed to by |
| /// Loc. Takes care of adjusting for any differences between the value's type |
| /// (which is the in-register type given by getRegType) and the in-memory type. |
| static void StoreRegisterToMemory(Value *V, MemRef Loc, tree type, |
| MDNode *AliasTag, LLVMBuilder &Builder) { |
| // NOTE: Needs to be kept in sync with getRegType. |
| assert(V->getType() == getRegType(type) && "Not of register type!"); |
| |
| // If storing the register directly to memory gives the right result, then |
| // just do that. |
| if (isDirectMemoryAccessSafe(V->getType(), type)) { |
| StoreToLocation(V, Loc, AliasTag, Builder); |
| return; |
| } |
| |
| // There is a discrepancy between the in-register type and the in-memory type. |
| switch (TREE_CODE(type)) { |
| default: |
| debug_tree(type); |
| llvm_unreachable("Unexpected type mismatch!"); |
| |
| case BOOLEAN_TYPE: |
| case ENUMERAL_TYPE: |
| case INTEGER_TYPE: { |
| // For integral types extend to an integer with size equal to the mode size. |
| // For example, when inserting a bool this probably extends it to an i8 or |
| // to an i32. This approach means we get the right result on both little |
| // and big endian machines. |
| unsigned Size = GET_MODE_BITSIZE(TYPE_MODE(type)); |
| Type *MemTy = IntegerType::get(Context, Size); |
| V = Builder.CreateIntCast(V, MemTy, /*isSigned*/ !TYPE_UNSIGNED(type)); |
| StoreToLocation(V, Loc, AliasTag, Builder); |
| break; |
| } |
| |
| case COMPLEX_TYPE: { |
| // Store the complex number component by component. |
| tree elt_type = main_type(type); |
| unsigned Stride = GET_MODE_SIZE(TYPE_MODE(elt_type)); |
| Value *RealPart = Builder.CreateExtractValue(V, 0); |
| Value *ImagPart = Builder.CreateExtractValue(V, 1); |
| StoreRegisterToMemory(RealPart, Loc, elt_type, AliasTag, Builder); |
| Loc = DisplaceLocationByUnits(Loc, Stride, Builder); |
| StoreRegisterToMemory(ImagPart, Loc, elt_type, AliasTag, Builder); |
| break; |
| } |
| |
| case VECTOR_TYPE: { |
| tree elt_type = main_type(type); |
| Type *EltRegTy = getRegType(elt_type); |
| unsigned NumElts = TYPE_VECTOR_SUBPARTS(type); |
| unsigned Size = GET_MODE_BITSIZE(TYPE_MODE(elt_type)); |
| // If, say, the register type is a vector of i1 but memory is laid out as a |
| // vector of i32 then extend the i1 vector to an i32 vector and store that. |
| if (EltRegTy->isIntegerTy() && EltRegTy->getIntegerBitWidth() != Size) { |
| // See if changing the element type to an integer with size equal to the |
| // mode size gives a vector type that corresponds to the in-memory layout. |
| Type *MemTy = IntegerType::get(Context, Size); |
| if (getDataLayout().getTypeAllocSizeInBits(MemTy) == Size) { |
| // It does! Extend the register value to a vector of that type then |
| // store it to memory. |
| Type *MemVecTy = VectorType::get(MemTy, NumElts); |
| V = Builder.CreateIntCast(V, MemVecTy, |
| /*isSigned*/ !TYPE_UNSIGNED(elt_type)); |
| StoreToLocation(V, Loc, AliasTag, Builder); |
| break; |
| } |
| } |
| // Otherwise, store the vector component by component. |
| unsigned Stride = GET_MODE_SIZE(TYPE_MODE(elt_type)); |
| for (unsigned i = 0; i != NumElts; ++i) { |
| Value *Idx = Builder.getInt32(i); |
| Value *Elt = Builder.CreateExtractElement(V, Idx); |
| StoreRegisterToMemory(Elt, Loc, elt_type, AliasTag, Builder); |
| if (i + 1 != NumElts) |
| Loc = DisplaceLocationByUnits(Loc, Stride, Builder); |
| } |
| break; |
| } |
| } |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // ... High-Level Methods ... |
| //===----------------------------------------------------------------------===// |
| |
| /// TheTreeToLLVM - Keep track of the current function being compiled. |
| TreeToLLVM *TheTreeToLLVM = 0; |
| |
| const DataLayout &getDataLayout() { return *TheTarget->getDataLayout(); } |
| |
| /// EmitDebugInfo - Return true if debug info is to be emitted for current |
| /// function. |
| bool TreeToLLVM::EmitDebugInfo() { |
| if (TheDebugInfo && !DECL_IGNORED_P(getFUNCTION_DECL())) |
| return true; |
| return false; |
| } |
| |
| TreeToLLVM::TreeToLLVM(tree fndecl) |
| : DL(getDataLayout()), Builder(Context, *TheFolder) { |
| FnDecl = fndecl; |
| AllocaInsertionPoint = 0; |
| Fn = 0; |
| ReturnBB = 0; |
| ReturnOffset = 0; |
| |
| if (EmitDebugInfo()) { |
| expanded_location Location = expand_location(DECL_SOURCE_LOCATION(fndecl)); |
| |
| if (Location.file) { |
| TheDebugInfo->setLocationFile(Location.file); |
| TheDebugInfo->setLocationLine(Location.line); |
| } else { |
| TheDebugInfo->setLocationFile(""); |
| TheDebugInfo->setLocationLine(0); |
| } |
| } |
| |
| assert(TheTreeToLLVM == 0 && "Reentering function creation?"); |
| TheTreeToLLVM = this; |
| } |
| |
| TreeToLLVM::~TreeToLLVM() { TheTreeToLLVM = 0; } |
| |
| //===----------------------------------------------------------------------===// |
| // ... Local declarations ... |
| //===----------------------------------------------------------------------===// |
| |
| /// isLocalDecl - Whether this declaration is local to the current function. |
| static bool isLocalDecl(tree decl) { |
| if (isa<CONST_DECL>(decl)) |
| return false; |
| assert(HAS_RTL_P(decl) && "Expected a declaration with RTL!"); |
| return |
| // GCC bug workaround: RESULT_DECL may not have DECL_CONTEXT set in thunks. |
| (!DECL_CONTEXT(decl) && isa<RESULT_DECL>(decl)) || |
| // Usual case. |
| (DECL_CONTEXT(decl) == current_function_decl && |
| !DECL_EXTERNAL(decl) && // External variables are not local. |
| !TREE_STATIC(decl) && // Static variables not considered local. |
| !isa<FUNCTION_DECL>(decl)); // Nested functions not considered local. |
| } |
| |
| /// set_decl_local - Remember the LLVM value for a GCC declaration. |
| Value *TreeToLLVM::set_decl_local(tree decl, Value *V) { |
| if (!isLocalDecl(decl)) |
| return SET_DECL_LLVM(decl, V); |
| if (V != NULL) |
| return LocalDecls[decl] = V; |
| LocalDecls.erase(decl); |
| return NULL; |
| } |
| |
| /// get_decl_local - Retrieve the LLVM value for a GCC declaration, or NULL. |
| Value *TreeToLLVM::get_decl_local(tree decl) { |
| if (!isLocalDecl(decl)) |
| return get_decl_llvm(decl); |
| DenseMap<tree, AssertingVH<Value> >::iterator I = LocalDecls.find(decl); |
| if (I != LocalDecls.end()) |
| return I->second; |
| return NULL; |
| } |
| |
| /// make_decl_local - Return the LLVM value for a GCC declaration if it exists. |
| /// Otherwise creates and returns an appropriate value. |
| Value *TreeToLLVM::make_decl_local(tree decl) { |
| if (!isLocalDecl(decl)) |
| return make_decl_llvm(decl); |
| |
| DenseMap<tree, AssertingVH<Value> >::iterator I = LocalDecls.find(decl); |
| if (I != LocalDecls.end()) |
| return I->second; |
| |
| switch (TREE_CODE(decl)) { |
| default: |
| debug_tree(decl); |
| llvm_unreachable("Unhandled local declaration!"); |
| |
| case RESULT_DECL: |
| case VAR_DECL: |
| EmitAutomaticVariableDecl(decl); |
| I = LocalDecls.find(decl); |
| assert(I != LocalDecls.end() && "Not a local variable?"); |
| return I->second; |
| } |
| } |
| |
| /// make_definition_local - Ensure that the body or initial value of the given |
| /// GCC declaration will be output, and return a declaration for it. |
| Value *TreeToLLVM::make_definition_local(tree decl) { |
| if (!isLocalDecl(decl)) |
| return make_definition_llvm(decl); |
| return make_decl_local(decl); |
| } |
| |
| /// llvm_store_scalar_argument - Store scalar argument ARGVAL of type |
| /// LLVMTY at location LOC. |
| static void llvm_store_scalar_argument(Value *Loc, Value *ArgVal, |
| llvm::Type *LLVMTy, unsigned RealSize, |
| LLVMBuilder &Builder) { |
| if (RealSize) { |
| // Not clear what this is supposed to do on big endian machines... |
| assert(!BYTES_BIG_ENDIAN && "Unsupported case - please report"); |
| // Do byte wise store because actual argument type does not match LLVMTy. |
| assert(ArgVal->getType()->isIntegerTy() && "Expected an integer value!"); |
| Type *StoreType = IntegerType::get(Context, RealSize * 8); |
| Loc = Builder.CreateBitCast(Loc, StoreType->getPointerTo()); |
| if (ArgVal->getType()->getPrimitiveSizeInBits() >= |
| StoreType->getPrimitiveSizeInBits()) |
| ArgVal = Builder.CreateTrunc(ArgVal, StoreType); |
| else |
| ArgVal = Builder.CreateZExt(ArgVal, StoreType); |
| Builder.CreateStore(ArgVal, Loc); |
| } else { |
| // This cast only involves pointers, therefore BitCast. |
| Loc = Builder.CreateBitCast(Loc, LLVMTy->getPointerTo()); |
| // FIXME: Pass down the alignment so we can do better than using 1 here. |
| Builder.CreateAlignedStore(ArgVal, Loc, 1); |
| } |
| } |
| |
| #ifndef LLVM_STORE_SCALAR_ARGUMENT |
| #define LLVM_STORE_SCALAR_ARGUMENT(LOC, ARG, TYPE, SIZE, BUILDER) \ |
| llvm_store_scalar_argument((LOC), (ARG), (TYPE), (SIZE), (BUILDER)) |
| #endif |
| |
| // This is true for types whose alignment when passed on the stack is less |
| // than the alignment of the type. |
| #define LLVM_BYVAL_ALIGNMENT_TOO_SMALL(T) \ |
| (LLVM_BYVAL_ALIGNMENT(T) && LLVM_BYVAL_ALIGNMENT(T) < TYPE_ALIGN_UNIT(T)) |
| |
| namespace { |
| /// FunctionPrologArgumentConversion - This helper class is driven by the ABI |
| /// definition for this target to figure out how to retrieve arguments from |
| /// the stack/regs coming into a function and store them into an appropriate |
| /// alloca for the argument. |
| struct FunctionPrologArgumentConversion : public DefaultABIClient { |
| tree FunctionDecl; |
| Function::arg_iterator &AI; |
| LLVMBuilder Builder; |
| std::vector<Value *> LocStack; |
| std::vector<std::string> NameStack; |
| CallingConv::ID &CallingConv; |
| unsigned Offset; |
| bool isShadowRet; |
| FunctionPrologArgumentConversion(tree FnDecl, Function::arg_iterator &ai, |
| const LLVMBuilder &B, CallingConv::ID &CC) |
| : FunctionDecl(FnDecl), AI(ai), Builder(B), CallingConv(CC), Offset(0), |
| isShadowRet(false) {} |
| |
| /// getCallingConv - This provides the desired CallingConv for the function. |
| CallingConv::ID getCallingConv(void) { return CallingConv; } |
| |
| void HandlePad(llvm::Type */*LLVMTy*/) { ++AI; } |
| |
| bool isShadowReturn() const { return isShadowRet; } |
| void setName(const std::string &Name) { NameStack.push_back(Name); } |
| void setLocation(Value *Loc) { LocStack.push_back(Loc); } |
| void clear() { |
| assert(NameStack.size() == 1 && LocStack.size() == 1 && "Imbalance!"); |
| NameStack.clear(); |
| LocStack.clear(); |
| } |
| |
| void HandleAggregateShadowResult(PointerType */*PtrArgTy*/, bool /*RetPtr*/) { |
| // If the function returns a structure by value, we transform the function |
| // to take a pointer to the result as the first argument of the function |
| // instead. |
| assert(AI != Builder.GetInsertBlock()->getParent()->arg_end() && |
| "No explicit return value?"); |
| AI->setName("agg.result"); |
| |
| isShadowRet = true; |
| tree ResultDecl = DECL_RESULT(FunctionDecl); |
| tree RetTy = TREE_TYPE(TREE_TYPE(FunctionDecl)); |
| if (TREE_CODE(RetTy) == TREE_CODE(TREE_TYPE(ResultDecl))) { |
| TheTreeToLLVM->set_decl_local(ResultDecl, AI); |
| ++AI; |
| return; |
| } |
| |
| // Otherwise, this must be something returned with NRVO. |
| assert(isa<REFERENCE_TYPE>(TREE_TYPE(ResultDecl)) && |
| "Not type match and not passing by reference?"); |
| // Create an alloca for the ResultDecl. |
| Value *Tmp = TheTreeToLLVM->CreateTemporary(AI->getType()); |
| Builder.CreateStore(AI, Tmp); |
| |
| TheTreeToLLVM->set_decl_local(ResultDecl, Tmp); |
| if (TheDebugInfo && !DECL_IGNORED_P(FunctionDecl)) { |
| TheDebugInfo->EmitDeclare(ResultDecl, dwarf::DW_TAG_auto_variable, |
| "agg.result", RetTy, Tmp, Builder); |
| } |
| ++AI; |
| } |
| |
| void HandleScalarShadowResult(PointerType */*PtrArgTy*/, bool /*RetPtr*/) { |
| assert(AI != Builder.GetInsertBlock()->getParent()->arg_end() && |
| "No explicit return value?"); |
| AI->setName("scalar.result"); |
| isShadowRet = true; |
| TheTreeToLLVM->set_decl_local(DECL_RESULT(FunctionDecl), AI); |
| ++AI; |
| } |
| |
| void HandleScalarArgument(llvm::Type *LLVMTy, tree /*type*/, |
| unsigned RealSize = 0) { |
| Value *ArgVal = AI; |
| if (ArgVal->getType() != LLVMTy) { |
| if (ArgVal->getType()->isPointerTy() && LLVMTy->isPointerTy()) { |
| // If this is GCC being sloppy about pointer types, insert a bitcast. |
| // See PR1083 for an example. |
| ArgVal = Builder.CreateBitCast(ArgVal, LLVMTy); |
| } else if (ArgVal->getType()->isDoubleTy()) { |
| // If this is a K&R float parameter, it got promoted to double. Insert |
| // the truncation to float now. |
| ArgVal = Builder.CreateFPTrunc(ArgVal, LLVMTy, NameStack.back()); |
| } else { |
| // If this is just a mismatch between integer types, this is due |
| // to K&R prototypes, where the forward proto defines the arg as int |
| // and the actual impls is a short or char. |
| assert(ArgVal->getType()->isIntegerTy(32) && LLVMTy->isIntegerTy() && |
| "Lowerings don't match?"); |
| ArgVal = Builder.CreateTrunc(ArgVal, LLVMTy, NameStack.back()); |
| } |
| } |
| assert(!LocStack.empty()); |
| Value *Loc = LocStack.back(); |
| LLVM_STORE_SCALAR_ARGUMENT(Loc, ArgVal, LLVMTy, RealSize, Builder); |
| AI->setName(NameStack.back()); |
| ++AI; |
| } |
| |
| void HandleByValArgument(llvm::Type */*LLVMTy*/, tree type) { |
| if (LLVM_BYVAL_ALIGNMENT_TOO_SMALL(type)) { |
| // Incoming object on stack is insufficiently aligned for the type. |
| // Make a correctly aligned copy. |
| assert(!LocStack.empty()); |
| Value *Loc = LocStack.back(); |
| // We cannot use field-by-field copy here; x86 long double is 16 |
| // bytes, but only 10 are copied. If the object is really a union |
| // we might need the other bytes. We must also be careful to use |
| // the smaller alignment. |
| Type *SBP = Type::getInt8PtrTy(Context); |
| Type *IntPtr = getDataLayout().getIntPtrType(Context, 0); |
| Value *Ops[5] = { |
| Builder.CreateCast(Instruction::BitCast, Loc, SBP), |
| Builder.CreateCast(Instruction::BitCast, AI, SBP), |
| ConstantInt::get(IntPtr, TREE_INT_CST_LOW(TYPE_SIZE_UNIT(type))), |
| Builder.getInt32(LLVM_BYVAL_ALIGNMENT(type)), Builder.getFalse() |
| }; |
| Type *ArgTypes[3] = { SBP, SBP, IntPtr }; |
| Builder.CreateCall( |
| Intrinsic::getDeclaration(TheModule, Intrinsic::memcpy, ArgTypes), |
| Ops); |
| |
| AI->setName(NameStack.back()); |
| } |
| ++AI; |
| } |
| |
| void HandleFCAArgument(llvm::Type */*LLVMTy*/, tree /*type*/) { |
| // Store the FCA argument into alloca. |
| assert(!LocStack.empty()); |
| Value *Loc = LocStack.back(); |
| Builder.CreateStore(AI, Loc); |
| AI->setName(NameStack.back()); |
| ++AI; |
| } |
| |
| void HandleAggregateResultAsScalar(Type */*ScalarTy*/, unsigned Off = 0) { |
| this->Offset = Off; |
| } |
| |
| void EnterField(unsigned FieldNo, llvm::Type *StructTy) { |
| NameStack.push_back(NameStack.back() + "." + utostr(FieldNo)); |
| |
| Value *Loc = LocStack.back(); |
| // This cast only involves pointers, therefore BitCast. |
| Loc = Builder.CreateBitCast(Loc, StructTy->getPointerTo()); |
| |
| Loc = Builder.CreateStructGEP(Loc, FieldNo, flag_verbose_asm ? "ntr" : ""); |
| LocStack.push_back(Loc); |
| } |
| void ExitField() { |
| NameStack.pop_back(); |
| LocStack.pop_back(); |
| } |
| }; |
| } |
| |
| // isPassedByVal - Return true if an aggregate of the specified type will be |
| // passed in memory byval. |
| static bool isPassedByVal(tree type, Type *Ty, std::vector<Type *> &ScalarArgs, |
| bool isShadowRet, CallingConv::ID CC) { |
| (void) type; |
| (void) Ty; |
| (void) ScalarArgs; |
| (void) isShadowRet; |
| (void) CC; // Not used by all ABI macros. |
| if (LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(type, Ty)) |
| return true; |
| |
| std::vector<Type *> Args; |
| if (LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(type, Ty, CC, Args) && |
| LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(Args, ScalarArgs, isShadowRet, |
| CC)) |
| // We want to pass the whole aggregate in registers but only some of the |
| // registers are available. |
| return true; |
| return false; |
| } |
| |
| void TreeToLLVM::StartFunctionBody() { |
| // TODO: Add support for dropping the leading '\1' in order to support |
| // unsigned bswap(unsigned) __asm__("llvm.bswap"); |
| // This would also require adjustments in make_decl_llvm. |
| |
| // Determine the FunctionType and calling convention for this function. |
| tree static_chain = cfun->static_chain_decl; |
| FunctionType *FTy; |
| CallingConv::ID CallingConv; |
| AttributeSet PAL; |
| |
| // If this is a K&R-style function: with a type that takes no arguments but |
| // with arguments none the less, then calculate the LLVM type from the list |
| // of arguments. |
| if (flag_functions_from_args || |
| (TYPE_ARG_TYPES(TREE_TYPE(FnDecl)) == 0 && DECL_ARGUMENTS(FnDecl))) { |
| SmallVector<tree, 8> Args; |
| for (tree Arg = DECL_ARGUMENTS(FnDecl); Arg; Arg = TREE_CHAIN(Arg)) |
| Args.push_back(Arg); |
| FTy = ConvertArgListToFnType(TREE_TYPE(FnDecl), Args, static_chain, |
| !flag_functions_from_args, CallingConv, PAL); |
| } else { |
| // Otherwise, just get the type from the function itself. |
| FTy = ConvertFunctionType(TREE_TYPE(FnDecl), FnDecl, static_chain, |
| CallingConv, PAL); |
| } |
| |
| // If we've already seen this function and created a prototype, and if the |
| // proto has the right LLVM type, just use it. |
| if (DECL_LOCAL_SET_P(FnDecl) && |
| cast<PointerType>(DECL_LOCAL(FnDecl)->getType())->getElementType() == |
| FTy) { |
| Fn = cast<Function>(DECL_LOCAL(FnDecl)); |
| assert(Fn->getCallingConv() == CallingConv && |
| "Calling convention disagreement between prototype and impl!"); |
| // The visibility can be changed from the last time we've seen this |
| // function. Set to current. |
| handleVisibility(FnDecl, Fn); |
| } else { |
| std::string Name = getAssemblerName(FnDecl); |
| Function *FnEntry = TheModule->getFunction(Name); |
| if (FnEntry) { |
| assert(FnEntry->getName() == Name && "Same entry, different name?"); |
| assert((FnEntry->isDeclaration() || |
| FnEntry->getLinkage() == Function::AvailableExternallyLinkage) && |
| "Multiple fns with same name and neither are external!"); |
| FnEntry->setName(""); // Clear name to avoid conflicts. |
| assert(FnEntry->getCallingConv() == CallingConv && |
| "Calling convention disagreement between prototype and impl!"); |
| } |
| |
| // Otherwise, either it exists with the wrong type or it doesn't exist. In |
| // either case create a new function. |
| Fn = Function::Create(FTy, Function::ExternalLinkage, Name, TheModule); |
| assert(Fn->getName() == Name && "Preexisting fn with the same name!"); |
| Fn->setCallingConv(CallingConv); |
| Fn->setAttributes(PAL); |
| |
| // If a previous proto existed with the wrong type, replace any uses of it |
| // with the actual function and delete the proto. |
| if (FnEntry) { |
| FnEntry->replaceAllUsesWith( |
| TheFolder->CreateBitCast(Fn, FnEntry->getType())); |
| changeLLVMConstant(FnEntry, Fn); |
| FnEntry->eraseFromParent(); |
| } |
| SET_DECL_LOCAL(FnDecl, Fn); |
| } |
| |
| // The function should not already have a body. |
| assert(Fn->empty() && "Function expanded multiple times!"); |
| |
| // Compute the linkage that the function should get. |
| if (false) { //FIXME DECL_LLVM_PRIVATE(FnDecl)) { |
| Fn->setLinkage(Function::PrivateLinkage); |
| } else if (false) { //FIXME DECL_LLVM_LINKER_PRIVATE(FnDecl)) { |
| Fn->setLinkage(Function::LinkerPrivateLinkage); |
| } else if (!TREE_PUBLIC(FnDecl) /*|| lang_hooks.llvm_is_in_anon(subr)*/) { |
| Fn->setLinkage(Function::InternalLinkage); |
| } else if (DECL_COMDAT(FnDecl)) { |
| Fn->setLinkage(Function::getLinkOnceLinkage(flag_odr)); |
| } else if (DECL_WEAK(FnDecl)) { |
| // The user may have explicitly asked for weak linkage - ignore flag_odr. |
| Fn->setLinkage(Function::WeakAnyLinkage); |
| } else if (DECL_ONE_ONLY(FnDecl)) { |
| Fn->setLinkage(Function::getWeakLinkage(flag_odr)); |
| } else if (DECL_EXTERNAL(FnDecl)) { |
| Fn->setLinkage(Function::AvailableExternallyLinkage); |
| } |
| |
| #ifdef TARGET_ADJUST_LLVM_LINKAGE |
| TARGET_ADJUST_LLVM_LINKAGE(Fn, FnDecl); |
| #endif /* TARGET_ADJUST_LLVM_LINKAGE */ |
| |
| Fn->setUnnamedAddr(!TREE_ADDRESSABLE(FnDecl)); |
| |
| // Handle visibility style |
| handleVisibility(FnDecl, Fn); |
| |
| // Register constructors and destructors. |
| if (DECL_STATIC_CONSTRUCTOR(FnDecl)) |
| register_ctor_dtor(Fn, DECL_INIT_PRIORITY(FnDecl), true); |
| if (DECL_STATIC_DESTRUCTOR(FnDecl)) |
| register_ctor_dtor(Fn, DECL_FINI_PRIORITY(FnDecl), false); |
| |
| // Handle attribute "aligned". |
| if (DECL_ALIGN(FnDecl) != FUNCTION_BOUNDARY) |
| Fn->setAlignment(DECL_ALIGN(FnDecl) / 8); |
| |
| // Handle functions in specified sections. |
| if (DECL_SECTION_NAME(FnDecl)) |
| Fn->setSection(TREE_STRING_POINTER(DECL_SECTION_NAME(FnDecl))); |
| |
| // Handle used Functions |
| if (lookup_attribute("used", DECL_ATTRIBUTES(FnDecl))) |
| AttributeUsedGlobals.insert(Fn); |
| |
| // Handle noinline Functions |
| if (lookup_attribute("noinline", DECL_ATTRIBUTES(FnDecl))) |
| Fn->addFnAttr(Attribute::NoInline); |
| |
| // Handle always_inline attribute |
| if (lookup_attribute("always_inline", DECL_ATTRIBUTES(FnDecl))) |
| Fn->addFnAttr(Attribute::AlwaysInline); |
| |
| // Pass inline keyword to optimizer. |
| if (DECL_DECLARED_INLINE_P(FnDecl)) |
| Fn->addFnAttr(Attribute::InlineHint); |
| |
| if (optimize_size) |
| Fn->addFnAttr(Attribute::OptimizeForSize); |
| |
| // Handle stack smashing protection. |
| if (flag_stack_protect == 1) |
| Fn->addFnAttr(Attribute::StackProtect); |
| else if (flag_stack_protect == 2) |
| Fn->addFnAttr(Attribute::StackProtectReq); |
| |
| // Handle naked attribute |
| if (lookup_attribute("naked", DECL_ATTRIBUTES(FnDecl))) |
| Fn->addFnAttr(Attribute::Naked); |
| |
| // Handle annotate attributes |
| if (DECL_ATTRIBUTES(FnDecl)) |
| AddAnnotateAttrsToGlobal(Fn, FnDecl); |
| |
| // Mark the function "nounwind" if not doing exception handling. |
| if (!flag_exceptions) |
| Fn->setDoesNotThrow(); |
| |
| if (flag_unwind_tables) |
| Fn->setHasUWTable(); |
| |
| // Create a new basic block for the function. |
| BasicBlock *EntryBlock = BasicBlock::Create(Context, "entry", Fn); |
| BasicBlocks[ENTRY_BLOCK_PTR] = EntryBlock; |
| Builder.SetInsertPoint(EntryBlock); |
| |
| if (EmitDebugInfo()) |
| TheDebugInfo->EmitFunctionStart(FnDecl, Fn); |
| |
| // Loop over all of the arguments to the function, setting Argument names and |
| // creating argument alloca's for the PARM_DECLs in case their address is |
| // exposed. |
| Function::arg_iterator AI = Fn->arg_begin(); |
| |
| // Rename and alloca'ify real arguments. |
| FunctionPrologArgumentConversion Client(FnDecl, AI, Builder, CallingConv); |
| DefaultABI ABIConverter(Client); |
| |
| // Handle the DECL_RESULT. |
| ABIConverter.HandleReturnType(TREE_TYPE(TREE_TYPE(FnDecl)), FnDecl, |
| DECL_BUILT_IN(FnDecl)); |
| // Remember this for use by FinishFunctionBody. |
| TheTreeToLLVM->ReturnOffset = Client.Offset; |
| |
| // Prepend the static chain (if any) to the list of arguments. |
| tree Args = static_chain ? static_chain : DECL_ARGUMENTS(FnDecl); |
| |
| // Scalar arguments processed so far. |
| std::vector<Type *> ScalarArgs; |
| while (Args) { |
| std::string Name = getDescriptiveName(Args); |
| if (Name.empty()) |
| Name = "unnamed_arg"; |
| |
| Type *ArgTy = ConvertType(TREE_TYPE(Args)); |
| bool isInvRef = isPassedByInvisibleReference(TREE_TYPE(Args)); |
| if (isInvRef || |
| (ArgTy->isVectorTy() && |
| LLVM_SHOULD_PASS_VECTOR_USING_BYVAL_ATTR(TREE_TYPE(Args)) && |
| !LLVM_BYVAL_ALIGNMENT_TOO_SMALL(TREE_TYPE(Args))) || |
| (!ArgTy->isSingleValueType() && |
| isPassedByVal(TREE_TYPE(Args), ArgTy, ScalarArgs, |
| Client.isShadowReturn(), CallingConv) && |
| !LLVM_BYVAL_ALIGNMENT_TOO_SMALL(TREE_TYPE(Args)))) { |
| // If the value is passed by 'invisible reference' or 'byval reference', |
| // the l-value for the argument IS the argument itself. But for byval |
| // arguments whose alignment as an argument is less than the normal |
| // alignment of the type (examples are x86-32 aggregates containing long |
| // double and large x86-64 vectors), we need to make the copy. |
| AI->setName(Name); |
| SET_DECL_LOCAL(Args, AI); |
| if (!isInvRef && EmitDebugInfo()) |
| TheDebugInfo->EmitDeclare(Args, dwarf::DW_TAG_arg_variable, Name, |
| TREE_TYPE(Args), AI, Builder); |
| ABIConverter.HandleArgument(TREE_TYPE(Args), ScalarArgs); |
| } else { |
| // Otherwise, we create an alloca to hold the argument value and provide |
| // an l-value. On entry to the function, we copy formal argument values |
| // into the alloca. |
| Value *Tmp = CreateTemporary(ArgTy, TYPE_ALIGN_UNIT(TREE_TYPE(Args))); |
| Tmp->setName(Name + "_addr"); |
| SET_DECL_LOCAL(Args, Tmp); |
| if (EmitDebugInfo()) { |
| TheDebugInfo->EmitDeclare(Args, dwarf::DW_TAG_arg_variable, Name, |
| TREE_TYPE(Args), Tmp, Builder); |
| } |
| |
| // Emit annotate intrinsic if arg has annotate attr |
| if (DECL_ATTRIBUTES(Args)) |
| EmitAnnotateIntrinsic(Tmp, Args); |
| |
| // Emit gcroot intrinsic if arg has attribute |
| if (isa<ACCESS_TYPE>(TREE_TYPE(Args)) && |
| lookup_attribute("gcroot", TYPE_ATTRIBUTES(TREE_TYPE(Args)))) |
| EmitTypeGcroot(Tmp); |
| |
| Client.setName(Name); |
| Client.setLocation(Tmp); |
| ABIConverter.HandleArgument(TREE_TYPE(Args), ScalarArgs); |
| Client.clear(); |
| } |
| |
| Args = Args == static_chain ? DECL_ARGUMENTS(FnDecl) : TREE_CHAIN(Args); |
| } |
| |
| // Loading the value of a PARM_DECL at this point yields its initial value. |
| // Remember this for use when materializing the reads implied by SSA default |
| // definitions. |
| SSAInsertionPoint = Builder.Insert( |
| CastInst::Create(Instruction::BitCast, |
| Constant::getNullValue(Type::getInt32Ty(Context)), |
| Type::getInt32Ty(Context)), |
| "ssa point"); |
| |
| // If this function has nested functions, we should handle a potential |
| // nonlocal_goto_save_area. |
| if (cfun->nonlocal_goto_save_area) { |
| // Not supported yet. |
| } |
| |
| if (EmitDebugInfo()) |
| TheDebugInfo->EmitStopPoint(Builder.GetInsertBlock(), Builder); |
| |
| // Ensure that local variables are output in the order that they were declared |
| // rather than in the order we come across them. This is only done to make the |
| // IR more readable and is not needed for correctness. |
| EmitVariablesInScope(DECL_INITIAL(FnDecl)); |
| } |
| |
| /// EmitVariablesInScope - Output a declaration for every variable in the |
| /// given scope. |
| void TreeToLLVM::EmitVariablesInScope(tree scope) { |
| for (tree t = BLOCK_VARS(scope); t; t = TREE_CHAIN(t)) |
| if (isa<VAR_DECL>(t)) |
| // If this is just the rotten husk of a variable that the gimplifier |
| // eliminated all uses of, but is preserving for debug info, ignore it. |
| if (!DECL_HAS_VALUE_EXPR_P(t)) |
| make_decl_local(t); |
| // Declare variables in contained scopes. |
| for (tree t = BLOCK_SUBBLOCKS(scope); t; t = BLOCK_CHAIN(t)) |
| EmitVariablesInScope(t); |
| } |
| |
| /// DefineSSAName - Use the given value as the definition of the given SSA name. |
| /// Returns the provided value as a convenience. |
| Value *TreeToLLVM::DefineSSAName(tree reg, Value *Val) { |
| assert(isa<SSA_NAME>(reg) && "Not an SSA name!"); |
| if (Value *ExistingValue = SSANames[reg]) { |
| if (Val != ExistingValue) { |
| assert(isSSAPlaceholder(ExistingValue) && "Multiply defined SSA name!"); |
| // Replace the placeholder with the value everywhere. This also updates |
| // the map entry, because it is a TrackingVH. |
| ExistingValue->replaceAllUsesWith(Val); |
| delete ExistingValue; |
| } |
| return Val; |
| } |
| return SSANames[reg] = Val; |
| } |
| |
| typedef SmallVector<std::pair<BasicBlock *, unsigned>, 8> PredVector; |
| typedef SmallVector<std::pair<BasicBlock *, tree>, 8> TreeVector; |
| typedef SmallVector<std::pair<BasicBlock *, Value *>, 8> ValueVector; |
| |
| /// PopulatePhiNodes - Populate generated phi nodes with their operands. |
| void TreeToLLVM::PopulatePhiNodes() { |
| PredVector Predecessors; |
| TreeVector IncomingValues; |
| ValueVector PhiArguments; |
| |
| for (unsigned Idx = 0, EIdx = (unsigned) PendingPhis.size(); Idx < EIdx; |
| ++Idx) { |
| // The phi node to process. |
| PhiRecord &P = PendingPhis[Idx]; |
| |
| // Extract the incoming value for each predecessor from the GCC phi node. |
| for (unsigned i = 0, e = gimple_phi_num_args(P.gcc_phi); i != e; ++i) { |
| // The incoming GCC basic block. |
| basic_block bb = gimple_phi_arg_edge(P.gcc_phi, i)->src; |
| |
| // The corresponding LLVM basic block. |
| DenseMap<basic_block, BasicBlock *>::iterator BI = BasicBlocks.find(bb); |
| assert(BI != BasicBlocks.end() && "GCC basic block not output?"); |
| |
| // The incoming GCC expression. |
| tree val = gimple_phi_arg(P.gcc_phi, i)->def; |
| |
| // Associate it with the LLVM basic block. |
| IncomingValues.push_back(std::make_pair(BI->second, val)); |
| |
| // Several LLVM basic blocks may be generated when emitting one GCC basic |
| // block. The additional blocks always occur immediately after the main |
| // basic block, and can be identified by the fact that they are nameless. |
| // Associate the incoming expression with all of them, since any of them |
| // may occur as a predecessor of the LLVM basic block containing the phi. |
| Function::iterator FI(BI->second), FE = Fn->end(); |
| for (++FI; FI != FE && !FI->hasName(); ++FI) { |
| assert(FI->getSinglePredecessor() == IncomingValues.back().first && |
| "Anonymous block does not continue predecessor!"); |
| IncomingValues.push_back(std::make_pair(FI, val)); |
| } |
| } |
| |
| // Sort the incoming values by basic block to help speed up queries. |
| std::sort(IncomingValues.begin(), IncomingValues.end()); |
| |
| // Get the LLVM predecessors for the basic block containing the phi node, |
| // and remember their positions in the list of predecessors (this is used |
| // to avoid adding phi operands in a non-deterministic order). |
| Predecessors.reserve(gimple_phi_num_args(P.gcc_phi)); // At least this many. |
| BasicBlock *PhiBB = P.PHI->getParent(); |
| unsigned Index = 0; |
| for (pred_iterator PI = pred_begin(PhiBB), PE = pred_end(PhiBB); PI != PE; |
| ++PI, ++Index) |
| Predecessors.push_back(std::make_pair(*PI, Index)); |
| |
| if (Predecessors.empty()) { |
| // FIXME: If this happens then GCC has a control flow edge where LLVM has |
| // none - something has gone wrong. For the moment be laid back about it |
| // because the fact we don't yet wire up exception handling code means it |
| // happens all the time in Ada and C++. |
| P.PHI->replaceAllUsesWith(UndefValue::get(P.PHI->getType())); |
| P.PHI->eraseFromParent(); |
| IncomingValues.clear(); |
| continue; |
| } |
| |
| // Sort the predecessors by basic block. In GCC, each predecessor occurs |
| // exactly once. However in LLVM a predecessor can occur several times, |
| // and then every copy of the predecessor must be associated with exactly |
| // the same incoming value in the phi node. Sorting the predecessors groups |
| // multiple occurrences together, making this easy to handle. |
| std::sort(Predecessors.begin(), Predecessors.end()); |
| |
| // Now iterate over the predecessors, setting phi operands as we go. |
| TreeVector::iterator VI = IncomingValues.begin(), VE = IncomingValues.end(); |
| PredVector::iterator PI = Predecessors.begin(), PE = Predecessors.end(); |
| PhiArguments.resize((unsigned) Predecessors.size()); |
| while (PI != PE) { |
| // The predecessor basic block. |
| BasicBlock *BB = PI->first; |
| |
| // Find the incoming value for this predecessor. |
| while (VI != VE && VI->first != BB) |
| ++VI; |
| assert(VI != VE && "No value for predecessor!"); |
| Value *Val = EmitRegister(VI->second); |
| |
| // Need to bitcast to the right type (useless_type_conversion_p). Place |
| // the bitcast at the end of the predecessor, before the terminator. |
| if (Val->getType() != P.PHI->getType()) |
| Val = new BitCastInst(Val, P.PHI->getType(), "", BB->getTerminator()); |
| |
| // Add the phi node arguments for all occurrences of this predecessor. |
| do { |
| // Place the argument at the position given by PI->second, which is the |
| // original position before sorting of the predecessor in the pred list. |
| // Since the predecessors were sorted non-deterministically (by pointer |
| // value), this ensures that the same bitcode is produced on any run. |
| PhiArguments[PI++->second] = std::make_pair(BB, Val); |
| } while (PI != PE && PI->first == BB); |
| } |
| |
| // Add the operands to the phi node. |
| for (ValueVector::iterator I = PhiArguments.begin(), E = PhiArguments.end(); |
| I != E; ++I) |
| P.PHI->addIncoming(I->second, I->first); |
| |
| IncomingValues.clear(); |
| PhiArguments.clear(); |
| Predecessors.clear(); |
| } |
| |
| PendingPhis.clear(); |
| } |
| |
| Function *TreeToLLVM::FinishFunctionBody() { |
| if (ReturnBB) { |
| // Insert the return block at the end of the function. |
| BeginBlock(ReturnBB); |
| |
| SmallVector<Value *, 4> RetVals; |
| |
| // If the function returns a value, get it into a register and return it now. |
| if (!Fn->getReturnType()->isVoidTy()) { |
| tree TreeRetVal = DECL_RESULT(FnDecl); |
| LValue ResultLV = EmitLV(TreeRetVal); |
| assert(!ResultLV.isBitfield() && "Bitfields not allowed here!"); |
| |
| if (!isa<AGGREGATE_TYPE>(TREE_TYPE(TreeRetVal)) && |
| !isa<COMPLEX_TYPE>(TREE_TYPE(TreeRetVal))) { |
| // If the DECL_RESULT is a scalar type, just load out the return value |
| // and return it. |
| LoadInst *Load = |
| Builder.CreateAlignedLoad(ResultLV.Ptr, ResultLV.getAlignment()); |
| RetVals.push_back(Builder.CreateBitCast(Load, Fn->getReturnType())); |
| } else { |
| uint64_t ResultSize = getDataLayout().getTypeAllocSize( |
| ConvertType(TREE_TYPE(TreeRetVal))); |
| uint64_t ReturnSize = |
| getDataLayout().getTypeAllocSize(Fn->getReturnType()); |
| |
| // The load does not necessarily start at the beginning of the aggregate |
| // (x86-64). |
| if (ReturnOffset >= ResultSize) { |
| // Also catches the case of an empty return value. |
| RetVals.push_back(UndefValue::get(Fn->getReturnType())); |
| } else { |
| // Advance to the point we want to load from. |
| if (ReturnOffset) { |
| ResultLV.Ptr = Builder |
| .CreateBitCast(ResultLV.Ptr, Type::getInt8PtrTy(Context)); |
| ResultLV.Ptr = Builder.CreateGEP( |
| ResultLV.Ptr, |
| ConstantInt::get(DL.getIntPtrType(Context, 0), ReturnOffset), |
| flag_verbose_asm ? "rtvl" : ""); |
| ResultLV.setAlignment( |
| MinAlign(ResultLV.getAlignment(), ReturnOffset)); |
| ResultSize -= ReturnOffset; |
| } |
| |
| // A place to build up the function return value. |
| MemRef ReturnLoc = CreateTempLoc(Fn->getReturnType()); |
| |
| // Copy out DECL_RESULT while being careful to not overrun the source or |
| // destination buffers. |
| uint64_t OctetsToCopy = std::min(ResultSize, ReturnSize); |
| EmitMemCpy( |
| ReturnLoc.Ptr, ResultLV.Ptr, Builder.getInt64(OctetsToCopy), |
| std::min(ReturnLoc.getAlignment(), ResultLV.getAlignment())); |
| |
| if (StructType *STy = |
| llvm::dyn_cast<StructType>(Fn->getReturnType())) { |
| llvm::Value *Idxs[2]; |
| Idxs[0] = Builder.getInt32(0); |
| bool Packed = STy->isPacked(); |
| for (unsigned ri = 0; ri < STy->getNumElements(); ++ri) { |
| Idxs[1] = Builder.getInt32(ri); |
| Value *GEP = Builder.CreateGEP(ReturnLoc.Ptr, Idxs, |
| flag_verbose_asm ? "mrv_gep" : ""); |
| Value *E = Builder.CreateAlignedLoad( |
| GEP, /*Align*/ Packed, flag_verbose_asm ? "mrv" : ""); |
| RetVals.push_back(E); |
| } |
| // If the return type specifies an empty struct then return one. |
| if (RetVals.empty()) |
| RetVals.push_back(UndefValue::get(Fn->getReturnType())); |
| } else { |
| // Otherwise, this aggregate result must be something that is returned |
| // in a scalar register for this target. We must bit convert the |
| // aggregate to the specified scalar type, which we do by casting the |
| // pointer and loading. |
| RetVals.push_back(Builder.CreateLoad(ReturnLoc.Ptr, "retval")); |
| } |
| } |
| } |
| } |
| if (RetVals.empty()) |
| Builder.CreateRetVoid(); |
| else if (RetVals.size() == 1 && |
| RetVals[0]->getType() == Fn->getReturnType()) { |
| Builder.CreateRet(RetVals[0]); |
| } else { |
| assert(Fn->getReturnType()->isAggregateType() && "Return type mismatch!"); |
| Builder.CreateAggregateRet(RetVals.data(), (unsigned) RetVals.size()); |
| } |
| } else { // !ReturnBB |
| BasicBlock *CurBB = Builder.GetInsertBlock(); |
| if (CurBB->getTerminator() == 0) { |
| if (CurBB->getName().empty() && CurBB->begin() == CurBB->end()) { |
| // If the previous block has no label and is empty, remove it: it is a |
| // post-terminator block. |
| CurBB->eraseFromParent(); |
| Builder.SetInsertPoint(&Fn->getBasicBlockList().back()); |
| } else { |
| // The previous block may contain code but no terminator if it finished |
| // with an unsupported GCC builtin. |
| Builder.CreateUnreachable(); |
| } |
| } |
| } |
| |
| // Populate phi nodes with their operands now that all ssa names have been |
| // defined and all basic blocks output. |
| PopulatePhiNodes(); |
| |
| // Now that phi nodes have been output, emit pending exception handling code. |
| EmitLandingPads(); |
| EmitFailureBlocks(); |
| |
| if (ReturnBB) { |
| // FIXME: This should be output just before the return call generated above. |
| // But because EmitFunctionEnd pops the region stack, that means that if the |
| // call to PopulatePhiNodes (for example) generates complicated debug info, |
| // then the debug info logic barfs. Testcases showing this are 20011126-2.c |
| // or pr42221.c from the gcc testsuite compiled with -g -O3. |
| if (EmitDebugInfo()) { |
| TheDebugInfo->EmitStopPoint(ReturnBB, Builder); |
| TheDebugInfo->EmitFunctionEnd(true); |
| } |
| } |
| |
| #ifdef NDEBUG |
| // When processing broken code it can be awkward to ensure that every SSA name |
| // that was used has a definition. So in this case we play it cool and create |
| // an artificial definition for such SSA names. The choice of definition does |
| // not matter because the compiler is going to exit with an error anyway. |
| if (errorcount || sorrycount) |
| #else |
| // When checks are enabled, complain if an SSA name was used but not defined. |
| #endif |
| for (DenseMap<tree, TrackingVH<Value> >::const_iterator |
| I = SSANames.begin(), |
| E = SSANames.end(); |
| I != E; ++I) { |
| Value *NameDef = I->second; |
| // If this is not a placeholder then the SSA name was defined. |
| if (!isSSAPlaceholder(NameDef)) |
| continue; |
| |
| // If an error occurred then replace the placeholder with undef. Thanks |
| // to this we can just bail out on errors, without having to worry about |
| // whether we defined every SSA name. |
| if (errorcount || sorrycount) { |
| NameDef->replaceAllUsesWith(UndefValue::get(NameDef->getType())); |
| delete NameDef; |
| } else { |
| debug_tree(I->first); |
| llvm_unreachable("SSA name never defined!"); |
| } |
| } |
| |
| return Fn; |
| } |
| |
| /// getBasicBlock - Find or create the LLVM basic block corresponding to BB. |
| BasicBlock *TreeToLLVM::getBasicBlock(basic_block bb) { |
| // If we already associated an LLVM basic block with BB, then return it. |
| DenseMap<basic_block, BasicBlock *>::iterator I = BasicBlocks.find(bb); |
| if (I != BasicBlocks.end()) |
| return I->second; |
| |
| // Otherwise, create a new LLVM basic block. |
| BasicBlock *BB = BasicBlock::Create(Context); |
| |
| // All basic blocks that directly correspond to GCC basic blocks (those |
| // created here) must have a name. All artificial basic blocks produced |
| // while generating code must be nameless. That way, artificial blocks |
| // can be easily identified. |
| |
| // Give the basic block a name. If the user specified -fverbose-asm then |
| // use the same naming scheme as GCC. |
| if (flag_verbose_asm) { |
| // If BB contains labels, name the LLVM basic block after the first label. |
| gimple stmt = first_stmt(bb); |
| if (stmt && gimple_code(stmt) == GIMPLE_LABEL) { |
| tree label = gimple_label_label(stmt); |
| const std::string &LabelName = getDescriptiveName(label); |
| if (!LabelName.empty()) |
| BB->setName("<" + LabelName + ">"); |
| } else { |
| // When there is no label, use the same name scheme as the GCC tree dumps. |
| Twine Index(bb->index); |
| BB->setName("<bb " + Index + ">"); |
| } |
| } else { |
| Twine Index(bb->index); |
| BB->setName(Index); |
| } |
| |
| return BasicBlocks[bb] = BB; |
| } |
| |
| /// getLabelDeclBlock - Lazily get and create a basic block for the specified |
| /// label. |
| BasicBlock *TreeToLLVM::getLabelDeclBlock(tree LabelDecl) { |
| assert(isa<LABEL_DECL>(LabelDecl) && "Isn't a label!?"); |
| if (DECL_LOCAL_SET_P(LabelDecl)) |
| return cast<BasicBlock>(DECL_LOCAL(LabelDecl)); |
| |
| basic_block bb = label_to_block(LabelDecl); |
| if (!bb) { |
| sorry("address of a non-local label"); |
| bb = ENTRY_BLOCK_PTR; // Do not crash. |
| } |
| |
| BasicBlock *BB = getBasicBlock(bb); |
| SET_DECL_LOCAL(LabelDecl, BB); |
| return BB; |
| } |
| |
| void TreeToLLVM::EmitBasicBlock(basic_block bb) { |
| location_t saved_loc = input_location; |
| ++NumBasicBlocks; |
| |
| // Avoid outputting a pointless branch at the end of the entry block. |
| if (bb != ENTRY_BLOCK_PTR) |
| BeginBlock(getBasicBlock(bb)); |
| |
| // Create an LLVM phi node for each GCC phi and define the associated ssa name |
| // using it. Do not populate with operands at this point since some ssa names |
| // the phi uses may not have been defined yet - phis are special this way. |
| for (gimple_stmt_iterator gsi = gsi_start_phis(bb); !gsi_end_p(gsi); |
| gsi_next(&gsi)) { |
| gimple gcc_phi = gsi_stmt(gsi); |
| // Skip virtual operands. |
| if (!is_gimple_reg(gimple_phi_result(gcc_phi))) |
| continue; |
| |
| // Create the LLVM phi node. |
| Type *Ty = getRegType(TREE_TYPE(gimple_phi_result(gcc_phi))); |
| PHINode *PHI = Builder.CreatePHI(Ty, gimple_phi_num_args(gcc_phi)); |
| |
| // The phi defines the associated ssa name. |
| tree name = gimple_phi_result(gcc_phi); |
| assert(isa<SSA_NAME>(name) && "PHI result not an SSA name!"); |
| if (flag_verbose_asm) |
| NameValue(PHI, name); |
| DefineSSAName(name, PHI); |
| |
| // The phi operands will be populated later - remember the phi node. |
| PhiRecord P = { gcc_phi, PHI }; |
| PendingPhis.push_back(P); |
| } |
| |
| // Render statements. |
| for (gimple_stmt_iterator gsi = gsi_start_bb(bb); !gsi_end_p(gsi); |
| gsi_next(&gsi)) { |
| gimple stmt = gsi_stmt(gsi); |
| input_location = gimple_location(stmt); |
| ++NumStatements; |
| |
| if (EmitDebugInfo()) { |
| if (gimple_has_location(stmt)) { |
| TheDebugInfo->setLocationFile(gimple_filename(stmt)); |
| TheDebugInfo->setLocationLine(gimple_lineno(stmt)); |
| } else { |
| TheDebugInfo->setLocationFile(""); |
| TheDebugInfo->setLocationLine(0); |
| } |
| TheDebugInfo->EmitStopPoint(Builder.GetInsertBlock(), Builder); |
| } |
| |
| switch (gimple_code(stmt)) { |
| default: |
| debug_gimple_stmt(stmt); |
| llvm_unreachable("Unhandled GIMPLE statement during LLVM emission!"); |
| |
| case GIMPLE_ASM: |
| RenderGIMPLE_ASM(stmt); |
| break; |
| |
| case GIMPLE_ASSIGN: |
| RenderGIMPLE_ASSIGN(stmt); |
| break; |
| |
| case GIMPLE_CALL: |
| RenderGIMPLE_CALL(stmt); |
| break; |
| |
| case GIMPLE_COND: |
| RenderGIMPLE_COND(stmt); |
| break; |
| |
| case GIMPLE_DEBUG: |
| // TODO: Output debug info rather than just discarding it. |
| break; |
| |
| case GIMPLE_EH_DISPATCH: |
| RenderGIMPLE_EH_DISPATCH(stmt); |
| break; |
| |
| case GIMPLE_GOTO: |
| RenderGIMPLE_GOTO(stmt); |
| break; |
| |
| case GIMPLE_LABEL: |
| case GIMPLE_NOP: |
| case GIMPLE_PREDICT: |
| break; |
| |
| case GIMPLE_RESX: |
| RenderGIMPLE_RESX(stmt); |
| break; |
| |
| case GIMPLE_RETURN: |
| RenderGIMPLE_RETURN(stmt); |
| break; |
| |
| case GIMPLE_SWITCH: |
| RenderGIMPLE_SWITCH(stmt); |
| break; |
| } |
| } |
| |
| if (EmitDebugInfo()) { |
| TheDebugInfo->setLocationFile(""); |
| TheDebugInfo->setLocationLine(0); |
| TheDebugInfo->EmitStopPoint(Builder.GetInsertBlock(), Builder); |
| } |
| |
| // Add a branch to the fallthru block. |
| edge e; |
| edge_iterator ei; |
| FOR_EACH_EDGE(e, ei, bb->succs) if (e->flags & EDGE_FALLTHRU) { |
| input_location = e->goto_locus; |
| // TODO: set the debug info location. |
| Builder.CreateBr(getBasicBlock(e->dest)); |
| break; |
| } |
| |
| input_location = saved_loc; |
| } |
| |
| Function *TreeToLLVM::EmitFunction() { |
| // Set up parameters and prepare for return, for the function. |
| StartFunctionBody(); |
| |
| // Output the basic blocks. |
| basic_block bb; |
| FOR_EACH_BB(bb) EmitBasicBlock(bb); |
| |
| // Wrap things up. |
| return FinishFunctionBody(); |
| } |
| |
| /// EmitAggregate - Store the specified tree node into the location given by |
| /// DestLoc. |
| void TreeToLLVM::EmitAggregate(tree exp, const MemRef &DestLoc) { |
| assert(isa<AGGREGATE_TYPE>(TREE_TYPE(exp)) && "Expected an aggregate type!"); |
| if (isa<CONSTRUCTOR>(exp)) { |
| EmitCONSTRUCTOR(exp, &DestLoc); |
| return; |
| } |
| LValue LV = EmitLV(exp); |
| assert(!LV.isBitfield() && "Bitfields containing aggregates not supported!"); |
| EmitAggregateCopy(DestLoc, |
| MemRef(LV.Ptr, LV.getAlignment(), TREE_THIS_VOLATILE(exp)), |
| TREE_TYPE(exp)); |
| } |
| |
| /// get_constant_alignment - Return the alignment of constant EXP in bits. |
| /// |
| static unsigned int get_constant_alignment(tree exp) { |
| unsigned int align = TYPE_ALIGN(TREE_TYPE(exp)); |
| #ifdef CONSTANT_ALIGNMENT |
| align = CONSTANT_ALIGNMENT(exp, align); |
| #endif |
| return align; |
| } |
| |
| /// EmitLV - Convert the specified l-value tree node to LLVM code, returning |
| /// the address of the result. |
| LValue TreeToLLVM::EmitLV(tree exp) { |
| LValue LV; |
| |
| switch (TREE_CODE(exp)) { |
| default: |
| debug_tree(exp); |
| llvm_unreachable("Unhandled lvalue expression!"); |
| |
| case PARM_DECL: |
| case VAR_DECL: |
| case FUNCTION_DECL: |
| case CONST_DECL: |
| case RESULT_DECL: |
| LV = EmitLV_DECL(exp); |
| break; |
| case ARRAY_RANGE_REF: |
| case ARRAY_REF: |
| LV = EmitLV_ARRAY_REF(exp); |
| break; |
| case COMPONENT_REF: |
| LV = EmitLV_COMPONENT_REF(exp); |
| break; |
| case BIT_FIELD_REF: |
| LV = EmitLV_BIT_FIELD_REF(exp); |
| break; |
| case REALPART_EXPR: |
| LV = EmitLV_XXXXPART_EXPR(exp, 0); |
| break; |
| case IMAGPART_EXPR: |
| LV = EmitLV_XXXXPART_EXPR(exp, 1); |
| break; |
| case SSA_NAME: |
| LV = EmitLV_SSA_NAME(exp); |
| break; |
| #if (GCC_MINOR > 5) |
| case MEM_REF: |
| LV = EmitLV_MEM_REF(exp); |
| break; |
| #endif |
| case TARGET_MEM_REF: |
| LV = EmitLV_TARGET_MEM_REF(exp); |
| break; |
| |
| // Constants. |
| case LABEL_DECL: { |
| LV = LValue(AddressOfLABEL_DECL(exp), 1); |
| break; |
| } |
| case CONSTRUCTOR: |
| case COMPLEX_CST: |
| case FIXED_CST: |
| case INTEGER_CST: |
| case REAL_CST: |
| case STRING_CST: |
| case VECTOR_CST: { |
| Value *Ptr = AddressOf(exp); |
| LV = LValue(Ptr, get_constant_alignment(exp) / 8); |
| break; |
| } |
| |
| // Type Conversion. |
| case VIEW_CONVERT_EXPR: |
| LV = EmitLV_VIEW_CONVERT_EXPR(exp); |
| break; |
| |
| // Trivial Cases. |
| case WITH_SIZE_EXPR: |
| LV = EmitLV_WITH_SIZE_EXPR(exp); |
| break; |
| case INDIRECT_REF: |
| LV = EmitLV_INDIRECT_REF(exp); |
| break; |
| #if (GCC_MINOR < 6) |
| case MISALIGNED_INDIRECT_REF: |
| LV = EmitLV_MISALIGNED_INDIRECT_REF(exp); |
| break; |
| #endif |
| } |
| |
| // Check that the type of the lvalue is indeed that of a pointer to the tree |
| // node. This may not hold for bitfields because the type of a bitfield need |
| // not match the type of the value being loaded out of it. Since LLVM has no |
| // void* type, don't insist that void* be converted to a specific LLVM type. |
| assert((LV.isBitfield() || isa<VOID_TYPE>(TREE_TYPE(exp)) || |
| LV.Ptr->getType() == ConvertType(TREE_TYPE(exp))->getPointerTo()) && |
| "LValue has wrong type!"); |
| |
| return LV; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // ... Utility Functions ... |
| //===----------------------------------------------------------------------===// |
| |
| /// CastToAnyType - Cast the specified value to the specified type making no |
| /// assumptions about the types of the arguments. This creates an inferred cast. |
| Value *TreeToLLVM::CastToAnyType(Value *Src, bool SrcIsSigned, Type *DestTy, |
| bool DestIsSigned) { |
| Type *SrcTy = Src->getType(); |
| |
| // Eliminate useless casts of a type to itself. |
| if (SrcTy == DestTy) |
| return Src; |
| |
| // Check whether the cast needs to be done in two steps, for example a pointer |
| // to float cast requires converting the pointer to an integer before casting |
| // to the float. |
| if (!CastInst::isCastable(SrcTy, DestTy)) { |
| unsigned SrcBits = SrcTy->getScalarSizeInBits(); |
| unsigned DestBits = DestTy->getScalarSizeInBits(); |
| if (SrcBits && !isa<IntegerType>(SrcTy)) { |
| Type *IntTy = IntegerType::get(Context, SrcBits); |
| Src = Builder.CreateBitCast(Src, IntTy); |
| return CastToAnyType(Src, SrcIsSigned, DestTy, DestIsSigned); |
| } |
| if (DestBits && !isa<IntegerType>(DestTy)) { |
| Type *IntTy = IntegerType::get(Context, DestBits); |
| Src = CastToAnyType(Src, SrcIsSigned, IntTy, DestIsSigned); |
| return Builder.CreateBitCast(Src, DestTy); |
| } |
| llvm_unreachable("Unable to cast between these types!"); |
| } |
| |
| // The types are different so we must cast. Use getCastOpcode to create an |
| // inferred cast opcode. |
| Instruction::CastOps opc = |
| CastInst::getCastOpcode(Src, SrcIsSigned, DestTy, DestIsSigned); |
| |
| // Generate the cast and return it. |
| return Builder.CreateCast(opc, Src, DestTy); |
| } |
| Constant *TreeToLLVM::CastToAnyType(Constant *Src, bool SrcIsSigned, |
| Type *DestTy, bool DestIsSigned) { |
| Type *SrcTy = Src->getType(); |
| |
| // Eliminate useless casts of a type to itself. |
| if (SrcTy == DestTy) |
| return Src; |
| |
| // Check whether the cast needs to be done in two steps, for example a pointer |
| // to float cast requires converting the pointer to an integer before casting |
| // to the float. |
| if (!CastInst::isCastable(SrcTy, DestTy)) { |
| unsigned SrcBits = SrcTy->getScalarSizeInBits(); |
| unsigned DestBits = DestTy->getScalarSizeInBits(); |
| if (SrcBits && !isa<IntegerType>(SrcTy)) { |
| Type *IntTy = IntegerType::get(Context, SrcBits); |
| Src = TheFolder->CreateBitCast(Src, IntTy); |
| return CastToAnyType(Src, SrcIsSigned, DestTy, DestIsSigned); |
| } |
| if (DestBits && !isa<IntegerType>(DestTy)) { |
| Type *IntTy = IntegerType::get(Context, DestBits); |
| Src = CastToAnyType(Src, SrcIsSigned, IntTy, DestIsSigned); |
| return TheFolder->CreateBitCast(Src, DestTy); |
| } |
| llvm_unreachable("Unable to cast between these types!"); |
| } |
| |
| // The types are different so we must cast. Use getCastOpcode to create an |
| // inferred cast opcode. |
| Instruction::CastOps opc = |
| CastInst::getCastOpcode(Src, SrcIsSigned, DestTy, DestIsSigned); |
| |
| // Generate the cast and return it. |
| return TheFolder->CreateCast(opc, Src, DestTy); |
| } |
| |
| /// CastFromSameSizeInteger - Cast an integer (or vector of integer) value to |
| /// the given scalar (resp. vector of scalar) type of the same bitwidth. |
| Value *TreeToLLVM::CastFromSameSizeInteger(Value *V, Type *Ty) { |
| assert(V->getType()->getScalarType()->isIntegerTy() && |
| "Expected an integer type!"); |
| Type *EltTy = Ty->getScalarType(); |
| if (EltTy->isIntegerTy()) { |
| // Already an integer/vector of integer - nothing to do. |
| assert(V->getType() == Ty && "Integer type not same size!"); |
| return V; |
| } |
| if (EltTy->isPointerTy()) { |
| // A pointer/vector of pointer - use inttoptr. |
| assert(V->getType()->getScalarType()->getPrimitiveSizeInBits() == |
| DL.getPointerSizeInBits(cast<PointerType>( |
| EltTy)->getAddressSpace()) && "Pointer type not same size!"); |
| return Builder.CreateIntToPtr(V, Ty); |
| } |
| // Everything else. |
| assert(Ty->isFPOrFPVectorTy() && "Expected a floating point type!"); |
| return Builder.CreateBitCast(V, Ty); // Will catch any size mismatch. |
| } |
| |
| /// CastToSameSizeInteger - Cast the specified scalar (or vector of scalar) |
| /// value to an integer (resp. vector of integer) of the same bit width. |
| Value *TreeToLLVM::CastToSameSizeInteger(Value *V) { |
| Type *OrigTy = V->getType(); |
| Type *OrigEltTy = OrigTy->getScalarType(); |
| if (OrigEltTy->isIntegerTy()) |
| // Already an integer/vector of integer - nothing to do. |
| return V; |
| if (OrigEltTy->isPointerTy()) |
| // A pointer/vector of pointer - form a (vector of) pointer sized integers. |
| return Builder.CreatePtrToInt(V, DL.getIntPtrType(OrigTy)); |
| // Everything else. |
| assert(OrigEltTy->isFloatingPointTy() && "Expected a floating point type!"); |
| unsigned BitWidth = OrigEltTy->getPrimitiveSizeInBits(); |
| Type *NewEltTy = IntegerType::get(Context, BitWidth); |
| if (VectorType *VecTy = llvm::dyn_cast<VectorType>(OrigTy)) { |
| Type *NewTy = VectorType::get(NewEltTy, VecTy->getNumElements()); |
| return Builder.CreateBitCast(V, NewTy); |
| } |
| return Builder.CreateBitCast(V, NewEltTy); |
| } |
| |
| /// CastToFPType - Cast the specified value to the specified type assuming |
| /// that V's type and Ty are floating point types. This arbitrates between |
| /// BitCast, FPTrunc and FPExt. |
| Value *TreeToLLVM::CastToFPType(Value *V, Type *Ty) { |
| unsigned SrcBits = V->getType()->getPrimitiveSizeInBits(); |
| unsigned DstBits = Ty->getPrimitiveSizeInBits(); |
| if (SrcBits == DstBits) |
| return V; |
| Instruction::CastOps opcode = |
| (SrcBits > DstBits ? Instruction::FPTrunc : Instruction::FPExt); |
| return Builder.CreateCast(opcode, V, Ty); |
| } |
| |
| /// CreateAnyAdd - Add two LLVM scalar values with the given GCC type. Does not |
| /// support complex numbers. The type is used to set overflow flags. |
| Value *TreeToLLVM::CreateAnyAdd(Value *LHS, Value *RHS, tree type) { |
| if (isa<FLOAT_TYPE>(type)) |
| return Builder.CreateFAdd(LHS, RHS); |
| return Builder.CreateAdd(LHS, RHS, "", hasNUW(type), hasNSW(type)); |
| } |
| |
| /// CreateAnyMul - Multiply two LLVM scalar values with the given GCC type. |
| /// Does not support complex numbers. The type is used to set overflow flags. |
| Value *TreeToLLVM::CreateAnyMul(Value *LHS, Value *RHS, tree type) { |
| if (isa<FLOAT_TYPE>(type)) |
| return Builder.CreateFMul(LHS, RHS); |
| return Builder.CreateMul(LHS, RHS, "", hasNUW(type), hasNSW(type)); |
| } |
| |
| /// CreateAnyNeg - Negate an LLVM scalar value with the given GCC type. Does |
| /// not support complex numbers. The type is used to set overflow flags. |
| Value *TreeToLLVM::CreateAnyNeg(Value *V, tree type) { |
| if (isa<FLOAT_TYPE>(type)) |
| return Builder.CreateFNeg(V); |
| return Builder.CreateNeg(V, "", hasNUW(type), hasNSW(type)); |
| } |
| |
| /// CreateAnySub - Subtract two LLVM scalar values with the given GCC type. |
| /// Does not support complex numbers. The type is used to set overflow flags. |
| Value *TreeToLLVM::CreateAnySub(Value *LHS, Value *RHS, tree type) { |
| if (isa<FLOAT_TYPE>(type)) |
| return Builder.CreateFSub(LHS, RHS); |
| return Builder.CreateSub(CastToSameSizeInteger(LHS), |
| CastToSameSizeInteger(RHS), "", hasNUW(type), |
| hasNSW(type)); |
| } |
| |
| /// CreateTemporary - Create a new alloca instruction of the specified type, |
| /// inserting it into the entry block and returning it. The resulting |
| /// instruction's type is a pointer to the specified type. |
| AllocaInst *TreeToLLVM::CreateTemporary(Type *Ty, unsigned align) { |
| if (AllocaInsertionPoint == 0) { |
| // Create a dummy instruction in the entry block as a marker to insert new |
| // alloc instructions before. It doesn't matter what this instruction is, |
| // it is dead. This allows us to insert allocas in order without having to |
| // scan for an insertion point. Use BitCast for int -> int |
| AllocaInsertionPoint = CastInst::Create( |
| Instruction::BitCast, Constant::getNullValue(Type::getInt32Ty(Context)), |
| Type::getInt32Ty(Context), "alloca point"); |
| // Insert it as the first instruction in the entry block. |
| Fn->begin()->getInstList() |
| .insert(Fn->begin()->begin(), AllocaInsertionPoint); |
| } |
| return new AllocaInst(Ty, 0, align, "", AllocaInsertionPoint); |
| } |
| |
| /// CreateTempLoc - Like CreateTemporary, but returns a MemRef. |
| MemRef TreeToLLVM::CreateTempLoc(Type *Ty) { |
| AllocaInst *AI = CreateTemporary(Ty); |
| // MemRefs do not allow alignment 0. |
| if (!AI->getAlignment()) |
| AI->setAlignment(DL.getPrefTypeAlignment(Ty)); |
| return MemRef(AI, AI->getAlignment(), false); |
| } |
| |
| /// BeginBlock - Add the specified basic block to the end of the function. If |
| /// the previous block falls through into it, add an explicit branch. |
| void TreeToLLVM::BeginBlock(BasicBlock *BB) { |
| BasicBlock *CurBB = Builder.GetInsertBlock(); |
| // If the previous block falls through to BB, add an explicit branch. |
| if (CurBB->getTerminator() == 0) { |
| // If the previous block has no label and is empty, remove it: it is a |
| // post-terminator block. |
| if (CurBB->getName().empty() && CurBB->begin() == CurBB->end()) |
| CurBB->eraseFromParent(); |
| else |
| // Otherwise, fall through to this block. |
| Builder.CreateBr(BB); |
| } |
| |
| // Add this block. |
| Fn->getBasicBlockList().push_back(BB); |
| Builder.SetInsertPoint(BB); // It is now the current block. |
| } |
| |
| static const unsigned TooCostly = 8; |
| |
| /// CostOfAccessingAllElements - Return a number representing the cost of doing |
| /// an element by element copy of the specified type. If it is clear that the |
| /// type should not be copied this way, for example because it has a bazillion |
| /// elements or contains fields of variable size, then TooCostly (or larger) is |
| /// returned. |
| static unsigned CostOfAccessingAllElements(tree type) { |
| // If the type is incomplete, enormous or of variable size then don't copy it. |
| if (!isInt64(TYPE_SIZE(type), true)) |
| return TooCostly; |
| |
| // A scalar copy has a cost of 1. |
| if (!isa<AGGREGATE_TYPE>(type)) |
| return 1; |
| |
| // The cost of a record type is the sum of the costs of its fields. |
| if (isa<RECORD_TYPE>(type)) { |
| Type *Ty = ConvertType(type); |
| unsigned TotalCost = 0; |
| for (tree Field = TYPE_FIELDS(type); Field; Field = TREE_CHAIN(Field)) { |
| if (!isa<FIELD_DECL>(Field)) |
| continue; |
| // If the field has no size, for example because it is a C-style variable |
| // length array, then just give up. |
| if (!DECL_SIZE(Field)) |
| return TooCostly; |
| // Ignore fields of size zero. This way, we don't give up just because |
| // there is a size zero field that is not represented in the LLVM type. |
| if (integer_zerop(DECL_SIZE(Field))) |
| continue; |
| // Bitfields are too hard - give up. |
| if (isBitfield(Field)) |
| return TooCostly; |
| // If there is no corresponding LLVM field then something funky is going |
| // on - just give up. |
| if (GetFieldIndex(Field, Ty) == INT_MAX) |
| return TooCostly; |
| TotalCost += CostOfAccessingAllElements(TREE_TYPE(Field)); |
| if (TotalCost >= TooCostly) |
| return TooCostly; |
| } |
| return TotalCost; |
| } |
| |
| // For array types, multiply the array length by the component cost. |
| if (isa<ARRAY_TYPE>(type)) { |
| // If this is an array with a funky component type then just give up. |
| if (!isSizeCompatible(TREE_TYPE(type))) |
| return TooCostly; |
| uint64_t ArrayLength = ArrayLengthOf(type); |
| if (ArrayLength >= TooCostly) |
| return TooCostly; |
| unsigned ComponentCost = CostOfAccessingAllElements(TREE_TYPE(type)); |
| if (ComponentCost >= TooCostly) |
| return TooCostly; |
| return ArrayLength * ComponentCost; |
| } |
| |
| // Other types are not supported. |
| return TooCostly; |
| } |
| |
| /// CopyElementByElement - Recursively traverse the potentially aggregate |
| /// src/dest ptrs, copying all of the elements. Helper for EmitAggregateCopy. |
| void TreeToLLVM::CopyElementByElement(MemRef DestLoc, MemRef SrcLoc, |
| tree type) { |
| if (!isa<AGGREGATE_TYPE>(type)) { |
| // Copy scalar. |
| MDNode *AliasTag = describeAliasSet(type); |
| StoreRegisterToMemory( |
| LoadRegisterFromMemory(SrcLoc, type, AliasTag, Builder), DestLoc, type, |
| AliasTag, Builder); |
| return; |
| } |
| |
| if (isa<RECORD_TYPE>(type)) { |
| // Ensure the source and destination are pointers to the record type. |
| Type *Ty = ConvertType(type); |
| DestLoc.Ptr = Builder.CreateBitCast(DestLoc.Ptr, Ty->getPointerTo()); |
| SrcLoc.Ptr = Builder.CreateBitCast(SrcLoc.Ptr, Ty->getPointerTo()); |
| |
| // Copy each field in turn. |
| for (tree Field = TYPE_FIELDS(type); Field; Field = TREE_CHAIN(Field)) { |
| if (!isa<FIELD_DECL>(Field)) |
| continue; |
| // Ignore fields of size zero. |
| if (integer_zerop(DECL_SIZE(Field))) |
| continue; |
| // Get the address of the field. |
| int FieldIdx = GetFieldIndex(Field, Ty); |
| assert(FieldIdx != INT_MAX && "Should not be copying if no LLVM field!"); |
| Value *DestFieldPtr = Builder.CreateStructGEP( |
| DestLoc.Ptr, FieldIdx, flag_verbose_asm ? "df" : ""); |
| Value *SrcFieldPtr = Builder.CreateStructGEP( |
| SrcLoc.Ptr, FieldIdx, flag_verbose_asm ? "sf" : ""); |
| |
| // Compute the field's alignment. |
| unsigned DestFieldAlign = DestLoc.getAlignment(); |
| unsigned SrcFieldAlign = SrcLoc.getAlignment(); |
| if (FieldIdx) { |
| DestFieldAlign = MinAlign(DestFieldAlign, getFieldAlignment(Field)); |
| SrcFieldAlign = MinAlign(SrcFieldAlign, getFieldAlignment(Field)); |
| } |
| |
| // Copy the field. |
| MemRef DestFieldLoc(DestFieldPtr, DestFieldAlign, DestLoc.Volatile); |
| MemRef SrcFieldLoc(SrcFieldPtr, SrcFieldAlign, SrcLoc.Volatile); |
| CopyElementByElement(DestFieldLoc, SrcFieldLoc, TREE_TYPE(Field)); |
| } |
| return; |
| } |
| |
| assert(isa<ARRAY_TYPE>(type) && "Expected an array!"); |
| |
| // Turn the source and destination into pointers to the component type. |
| Type *CompType = ConvertType(TREE_TYPE(type)); |
| DestLoc.Ptr = Builder.CreateBitCast(DestLoc.Ptr, CompType->getPointerTo()); |
| SrcLoc.Ptr = Builder.CreateBitCast(SrcLoc.Ptr, CompType->getPointerTo()); |
| |
| // Copy each component in turn. |
| unsigned ComponentBytes = getDataLayout().getTypeAllocSize(CompType); |
| unsigned ArrayLength = ArrayLengthOf(type); |
| for (unsigned i = 0; i != ArrayLength; ++i) { |
| // Get the address of the component. |
| Value *DestCompPtr = DestLoc.Ptr, *SrcCompPtr = SrcLoc.Ptr; |
| if (i) { |
| DestCompPtr = Builder.CreateConstInBoundsGEP1_32( |
| DestCompPtr, i, flag_verbose_asm ? "da" : ""); |
| SrcCompPtr = Builder.CreateConstInBoundsGEP1_32( |
| SrcCompPtr, i, flag_verbose_asm ? "sa" : ""); |
| } |
| |
| // Compute the component's alignment. |
| unsigned DestCompAlign = DestLoc.getAlignment(); |
| unsigned SrcCompAlign = SrcLoc.getAlignment(); |
| if (i) { |
| DestCompAlign = MinAlign(DestCompAlign, i * ComponentBytes); |
| SrcCompAlign = MinAlign(SrcCompAlign, i * ComponentBytes); |
| } |
| |
| // Copy the component. |
| MemRef DestCompLoc(DestCompPtr, DestCompAlign, DestLoc.Volatile); |
| MemRef SrcCompLoc(SrcCompPtr, SrcCompAlign, SrcLoc.Volatile); |
| CopyElementByElement(DestCompLoc, SrcCompLoc, TREE_TYPE(type)); |
| } |
| } |
| |
| #ifndef TARGET_DRAGONEGG_MEMCPY_COST |
| #define TARGET_DRAGONEGG_MEMCPY_COST 5 |
| #endif |
| |
| /// EmitAggregateCopy - Copy the elements from SrcLoc to DestLoc, using the |
| /// GCC type specified by GCCType to know which elements to copy. |
| void TreeToLLVM::EmitAggregateCopy(MemRef DestLoc, MemRef SrcLoc, tree type) { |
| if (DestLoc.Ptr == SrcLoc.Ptr && !DestLoc.Volatile && !SrcLoc.Volatile) |
| return; // noop copy. |
| |
| // If the type is small, copy element by element instead of using memcpy. |
| unsigned Cost = CostOfAccessingAllElements(type); |
| if (Cost < TooCostly && Cost < TARGET_DRAGONEGG_MEMCPY_COST) { |
| CopyElementByElement(DestLoc, SrcLoc, type); |
| return; |
| } |
| |
| Value *TypeSize = EmitRegister(TYPE_SIZE_UNIT(type)); |
| EmitMemCpy(DestLoc.Ptr, SrcLoc.Ptr, TypeSize, |
| std::min(DestLoc.getAlignment(), SrcLoc.getAlignment())); |
| } |
| |
| /// ZeroElementByElement - Recursively traverse the potentially aggregate |
| /// DestLoc, zero'ing all of the elements. Helper for EmitAggregateZero. |
| void TreeToLLVM::ZeroElementByElement(MemRef DestLoc, tree type) { |
| if (!isa<AGGREGATE_TYPE>(type)) { |
| // Zero scalar. |
| StoreRegisterToMemory(Constant::getNullValue(getRegType(type)), DestLoc, |
| type, describeAliasSet(type), Builder); |
| return; |
| } |
| |
| if (isa<RECORD_TYPE>(type)) { |
| // Ensure the pointer is to the record type. |
| Type *Ty = ConvertType(type); |
| DestLoc.Ptr = Builder.CreateBitCast(DestLoc.Ptr, Ty->getPointerTo()); |
| |
| // Zero each field in turn. |
| for (tree Field = TYPE_FIELDS(type); Field; Field = TREE_CHAIN(Field)) { |
| if (!isa<FIELD_DECL>(Field)) |
| continue; |
| // Ignore fields of size zero. |
| if (integer_zerop(DECL_SIZE(Field))) |
| continue; |
| // Get the address of the field. |
| int FieldIdx = GetFieldIndex(Field, Ty); |
| assert(FieldIdx != INT_MAX && "Should not be zeroing if no LLVM field!"); |
| Value *FieldPtr = Builder.CreateStructGEP(DestLoc.Ptr, FieldIdx, |
| flag_verbose_asm ? "zf" : ""); |
| |
| // Compute the field's alignment. |
| unsigned FieldAlign = DestLoc.getAlignment(); |
| if (FieldIdx) |
| FieldAlign = MinAlign(FieldAlign, getFieldAlignment(Field)); |
| |
| // Zero the field. |
| MemRef FieldLoc(FieldPtr, FieldAlign, DestLoc.Volatile); |
| ZeroElementByElement(FieldLoc, TREE_TYPE(Field)); |
| } |
| return; |
| } |
| |
| assert(isa<ARRAY_TYPE>(type) && "Expected an array!"); |
| |
| // Turn the pointer into a pointer to the component type. |
| Type *CompType = ConvertType(TREE_TYPE(type)); |
| DestLoc.Ptr = Builder.CreateBitCast(DestLoc.Ptr, CompType->getPointerTo()); |
| |
| // Zero each component in turn. |
| unsigned ComponentBytes = getDataLayout().getTypeAllocSize(CompType); |
| unsigned ArrayLength = ArrayLengthOf(type); |
| for (unsigned i = 0; i != ArrayLength; ++i) { |
| // Get the address of the component. |
| Value *CompPtr = DestLoc.Ptr; |
| if (i) |
| CompPtr = Builder.CreateConstInBoundsGEP1_32( |
| CompPtr, i, flag_verbose_asm ? "za" : ""); |
| |
| // Compute the component's alignment. |
| unsigned CompAlign = DestLoc.getAlignment(); |
| if (i) |
| CompAlign = MinAlign(CompAlign, i * ComponentBytes); |
| |
| // Zero the component. |
| MemRef CompLoc(CompPtr, CompAlign, DestLoc.Volatile); |
| ZeroElementByElement(CompLoc, TREE_TYPE(type)); |
| } |
| } |
| |
| #ifndef TARGET_DRAGONEGG_MEMSET_COST |
| #define TARGET_DRAGONEGG_MEMSET_COST 5 |
| #endif |
| |
| /// EmitAggregateZero - Zero the elements of DestLoc. |
| void TreeToLLVM::EmitAggregateZero(MemRef DestLoc, tree type) { |
| // If the type is small, zero element by element instead of using memset. |
| unsigned Cost = CostOfAccessingAllElements(type); |
| if (Cost < TooCostly && Cost < TARGET_DRAGONEGG_MEMSET_COST) { |
| ZeroElementByElement(DestLoc, type); |
| return; |
| } |
| |
| EmitMemSet(DestLoc.Ptr, Builder.getInt8(0), |
| EmitRegister(TYPE_SIZE_UNIT(type)), DestLoc.getAlignment()); |
| } |
| |
| Value *TreeToLLVM::EmitMemCpy(Value *DestPtr, Value *SrcPtr, Value *Size, |
| unsigned Align) { |
| |
| Type *SBP = Type::getInt8PtrTy(Context); |
| Type *IntPtr = DL.getIntPtrType(DestPtr->getType()); |
| Value *Ops[5] = { Builder.CreateBitCast(DestPtr, SBP), |
| Builder.CreateBitCast(SrcPtr, SBP), |
| Builder.CreateIntCast(Size, IntPtr, /*isSigned*/ true), |
| Builder.getInt32(Align), Builder.getFalse() }; |
| Type *ArgTypes[3] = { SBP, SBP, IntPtr }; |
| |
| Builder.CreateCall( |
| Intrinsic::getDeclaration(TheModule, Intrinsic::memcpy, ArgTypes), Ops); |
| return Ops[0]; |
| } |
| |
| Value *TreeToLLVM::EmitMemMove(Value *DestPtr, Value *SrcPtr, Value *Size, |
| unsigned Align) { |
| Type *SBP = Type::getInt8PtrTy(Context); |
| Type *IntPtr = DL.getIntPtrType(DestPtr->getType()); |
| Value *Ops[5] = { Builder.CreateBitCast(DestPtr, SBP), |
| Builder.CreateBitCast(SrcPtr, SBP), |
| Builder.CreateIntCast(Size, IntPtr, /*isSigned*/ true), |
| Builder.getInt32(Align), Builder.getFalse() }; |
| Type *ArgTypes[3] = { SBP, SBP, IntPtr }; |
| |
| Builder.CreateCall( |
| Intrinsic::getDeclaration(TheModule, Intrinsic::memmove, ArgTypes), Ops); |
| return Ops[0]; |
| } |
| |
| Value *TreeToLLVM::EmitMemSet(Value *DestPtr, Value *SrcVal, Value *Size, |
| unsigned Align) { |
| Type *SBP = Type::getInt8PtrTy(Context); |
| Type *IntPtr = DL.getIntPtrType(DestPtr->getType()); |
| Value *Ops[5] = { Builder.CreateBitCast(DestPtr, SBP), |
| Builder.CreateIntCast(SrcVal, Type::getInt8Ty(Context), |
| /*isSigned*/ true), |
| Builder.CreateIntCast(Size, IntPtr, /*isSigned*/ true), |
| Builder.getInt32(Align), Builder.getFalse() }; |
| Type *ArgTypes[2] = { SBP, IntPtr }; |
| |
| Builder.CreateCall( |
| Intrinsic::getDeclaration(TheModule, Intrinsic::memset, ArgTypes), Ops); |
| return Ops[0]; |
| } |
| |
| // Emits code to do something for a type attribute |
| void TreeToLLVM::EmitTypeGcroot(Value *V) { |
| // GC intrinsics can only be used in functions which specify a collector. |
| Fn->setGC("shadow-stack"); |
| |
| Function *gcrootFun = Intrinsic::getDeclaration(TheModule, Intrinsic::gcroot); |
| |
| // The idea is that it's a pointer to type "Value" |
| // which is opaque* but the routine expects i8** and i8*. |
| PointerType *Ty = Type::getInt8PtrTy(Context); |
| V = Builder.CreateBitCast(V, Ty->getPointerTo()); |
| |
| Value *Ops[2] = { V, ConstantPointerNull::get(Ty) }; |
| |
| Builder.CreateCall(gcrootFun, Ops); |
| } |
| |
| // Emits annotate intrinsic if the decl has the annotate attribute set. |
| void TreeToLLVM::EmitAnnotateIntrinsic(Value *V, tree decl) { |
| |
| // Handle annotate attribute on global. |
| tree annotateAttr = lookup_attribute("annotate", DECL_ATTRIBUTES(decl)); |
| |
| if (!annotateAttr) |
| return; |
| |
| Function *annotateFun = |
| Intrinsic::getDeclaration(TheModule, Intrinsic::var_annotation); |
| |
| // Get file and line number |
| Constant *lineNo = |
| ConstantInt::get(Type::getInt32Ty(Context), DECL_SOURCE_LINE(decl)); |
| Constant *file = ConvertMetadataStringToGV(DECL_SOURCE_FILE(decl)); |
| Type *SBP = Type::getInt8PtrTy(Context); |
| file = TheFolder->CreateBitCast(file, SBP); |
| |
| // There may be multiple annotate attributes. Pass return of lookup_attr |
| // to successive lookups. |
| while (annotateAttr) { |
| |
| // Each annotate attribute is a tree list. |
| // Get value of list which is our linked list of args. |
| tree args = TREE_VALUE(annotateAttr); |
| |
| // Each annotate attribute may have multiple args. |
| // Treat each arg as if it were a separate annotate attribute. |
| for (tree a = args; a; a = TREE_CHAIN(a)) { |
| // Each element of the arg list is a tree list, so get value |
| tree val = TREE_VALUE(a); |
| |
| // Assert its a string, and then get that string. |
| assert(isa<STRING_CST>(val) && |
| "Annotate attribute arg should always be a string"); |
| Constant *strGV = AddressOf(val); |
| Value *Ops[4] = { Builder.CreateBitCast(V, SBP), |
| Builder.CreateBitCast(strGV, SBP), file, lineNo }; |
| |
| Builder.CreateCall(annotateFun, Ops); |
| } |
| |
| // Get next annotate attribute. |
| annotateAttr = TREE_CHAIN(annotateAttr); |
| if (annotateAttr) |
| annotateAttr = lookup_attribute("annotate", annotateAttr); |
| } |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // ... Basic Lists and Binding Scopes ... |
| //===----------------------------------------------------------------------===// |
| |
| /// EmitAutomaticVariableDecl - Emit the function-local decl to the current |
| /// function and set DECL_LOCAL for the decl to the right pointer. |
| void TreeToLLVM::EmitAutomaticVariableDecl(tree decl) { |
| // If this is just the rotten husk of a variable that the gimplifier |
| // eliminated all uses of, but is preserving for debug info, ignore it. |
| if (isa<VAR_DECL>(decl) && DECL_HAS_VALUE_EXPR_P(decl)) |
| return; |
| |
| tree type = TREE_TYPE(decl); |
| Type *Ty; // Type to allocate |
| Value *Size = 0; // Amount to alloca (null for 1) |
| |
| if (DECL_SIZE(decl) == 0) { // Variable with incomplete type. |
| if (DECL_INITIAL(decl) == 0) |
| return; // Error message was already done; now avoid a crash. |
| debug_tree(decl); |
| llvm_unreachable("Initializer will decide the size of this array?"); |
| } else if (isa<INTEGER_CST>(DECL_SIZE_UNIT(decl))) { |
| // Variable of fixed size that goes on the stack. |
| Ty = ConvertType(type); |
| } else { |
| // Compute the variable's size in bytes. |
| Size = EmitRegister(DECL_SIZE_UNIT(decl)); |
| Ty = Type::getInt8Ty(Context); |
| } |
| |
| unsigned Alignment = DECL_ALIGN(decl) / 8; // Alignment in octets. |
| assert(Alignment != 0 && "Local variable with unknown alignment!"); |
| |
| // If this is the alignment we would have given the variable anyway and it was |
| // not user specified then don't use an explicit alignment, making the IR look |
| // more portable. |
| if (!DECL_USER_ALIGN(decl) && |
| Alignment == getDataLayout().getABITypeAlignment(Ty)) |
| Alignment = 0; |
| |
| // Insert an alloca for this variable. |
| AllocaInst *AI; |
| if (!Size) { // Fixed size alloca -> entry block. |
| AI = CreateTemporary(Ty); |
| } else { |
| AI = Builder.CreateAlloca(Ty, Size); |
| } |
| NameValue(AI, decl); |
| |
| AI->setAlignment(Alignment); |
| |
| SET_DECL_LOCAL(decl, AI); |
| |
| // Handle annotate attributes |
| if (DECL_ATTRIBUTES(decl)) |
| EmitAnnotateIntrinsic(AI, decl); |
| |
| // Handle gcroot attribute |
| if (isa<ACCESS_TYPE>(TREE_TYPE(decl)) && |
| lookup_attribute("gcroot", TYPE_ATTRIBUTES(TREE_TYPE(decl)))) { |
| // We should null out local variables so that a stack crawl |
| // before initialization doesn't get garbage results to follow. |
| Type *T = cast<PointerType>(AI->getType())->getElementType(); |
| EmitTypeGcroot(AI); |
| Builder.CreateStore(Constant::getNullValue(T), AI); |
| } |
| |
| if (EmitDebugInfo()) { |
| if (DECL_NAME(decl) || isa<RESULT_DECL>(decl)) { |
| TheDebugInfo->EmitDeclare(decl, dwarf::DW_TAG_auto_variable, |
| AI->getName(), TREE_TYPE(decl), AI, Builder); |
| } |
| } |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // ... Control Flow ... |
| //===----------------------------------------------------------------------===// |
| |
| /// ConvertTypeInfo - Convert an exception handling type info into a pointer to |
| /// the associated runtime type info object. |
| static Constant *ConvertTypeInfo(tree type) { |
| // TODO: Once pass_ipa_free_lang is made a default pass, remove the call to |
| // lookup_type_for_runtime below. |
| if (isa<TYPE>(type)) |
| type = lookup_type_for_runtime(type); |
| STRIP_NOPS(type); |
| if (isa<ADDR_EXPR>(type)) |
| type = TREE_OPERAND(type, 0); |
| return AddressOf(type); |
| } |
| |
| /// getExceptionPtr - Return the local holding the exception pointer for the |
| /// given exception handling region, creating it if necessary. |
| AllocaInst *TreeToLLVM::getExceptionPtr(int RegionNo) { |
| assert(RegionNo >= 0 && "Invalid exception handling region!"); |
| |
| if ((unsigned) RegionNo >= ExceptionPtrs.size()) |
| ExceptionPtrs.resize(RegionNo + 1, 0); |
| |
| AllocaInst *&ExceptionPtr = ExceptionPtrs[RegionNo]; |
| |
| if (!ExceptionPtr) { |
| ExceptionPtr = CreateTemporary(Type::getInt8PtrTy(Context)); |
| ExceptionPtr->setName("exc_tmp"); |
| } |
| |
| return ExceptionPtr; |
| } |
| |
| /// getExceptionFilter - Return the local holding the filter value for the |
| /// given exception handling region, creating it if necessary. |
| AllocaInst *TreeToLLVM::getExceptionFilter(int RegionNo) { |
| assert(RegionNo >= 0 && "Invalid exception handling region!"); |
| |
| if ((unsigned) RegionNo >= ExceptionFilters.size()) |
| ExceptionFilters.resize(RegionNo + 1, 0); |
| |
| AllocaInst *&ExceptionFilter = ExceptionFilters[RegionNo]; |
| |
| if (!ExceptionFilter) { |
| ExceptionFilter = CreateTemporary(Type::getInt32Ty(Context)); |
| ExceptionFilter->setName("filt_tmp"); |
| } |
| |
| return ExceptionFilter; |
| } |
| |
| /// getFailureBlock - Return the basic block containing the failure code for |
| /// the given exception handling region, creating it if necessary. |
| BasicBlock *TreeToLLVM::getFailureBlock(int RegionNo) { |
| assert(RegionNo >= 0 && "Invalid exception handling region!"); |
| |
| if ((unsigned) RegionNo >= FailureBlocks.size()) |
| FailureBlocks.resize(RegionNo + 1, 0); |
| |
| BasicBlock *&FailureBlock = FailureBlocks[RegionNo]; |
| |
| if (!FailureBlock) |
| FailureBlock = BasicBlock::Create(Context, "fail"); |
| |
| return FailureBlock; |
| } |
| |
| /// EmitLandingPads - Emit EH landing pads. |
| void TreeToLLVM::EmitLandingPads() { |
| // If there are no invokes then there is nothing to do. |
| if (NormalInvokes.empty()) |
| return; |
| |
| // If a GCC post landing pad is shared by several exception handling regions, |
| // or if there is a normal edge to it, then create LLVM landing pads for each |
| // eh region. The landing pad instruction will then go in the LLVM landing |
| // pad, which then branches to the GCC post landing pad. |
| for (unsigned LPadNo = 1; LPadNo < NormalInvokes.size(); ++LPadNo) { |
| // Get the list of invokes for this GCC landing pad. |
| SmallVector<InvokeInst *, 8> &InvokesForPad = NormalInvokes[LPadNo]; |
| |
| if (InvokesForPad.empty()) |
| continue; |
| |
| // All of the invokes unwind to the GCC post landing pad. |
| BasicBlock *PostPad = InvokesForPad[0]->getUnwindDest(); |
| |
| // If the number of invokes is equal to the number of predecessors of the |
| // post landing pad then it follows that no other GCC landing pad has any |
| // invokes that unwind to this post landing pad, and also that no normal |
| // edges land at this post pad. In this case there is no need to create |
| // an LLVM specific landing pad. |
| if ((unsigned) std::distance(pred_begin(PostPad), pred_end(PostPad)) == |
| InvokesForPad.size()) |
| continue; |
| |
| // Create the LLVM landing pad right before the GCC post landing pad. |
| BasicBlock *LPad = BasicBlock::Create(Context, "lpad", Fn, PostPad); |
| |
| // Redirect invoke unwind edges from the GCC post landing pad to LPad. |
| for (unsigned i = 0, e = InvokesForPad.size(); i < e; ++i) |
| InvokesForPad[i]->setSuccessor(1, LPad); |
| |
| // If there are any PHI nodes in PostPad, we need to update them to merge |
| // incoming values from LPad instead. |
| pred_iterator PB = pred_begin(LPad), PE = pred_end(LPad); |
| for (BasicBlock::iterator II = PostPad->begin(); isa<PHINode>(II);) { |
| PHINode *PN = cast<PHINode>(II++); |
| |
| // Check to see if all of the values coming in via invoke unwind edges are |
| // the same. If so, we don't need to create a new PHI node. |
| Value *InVal = PN->getIncomingValueForBlock(*PB); |
| for (pred_iterator PI = PB; PI != PE; ++PI) { |
| if (PI != PB && InVal != PN->getIncomingValueForBlock(*PI)) { |
| InVal = 0; |
| break; |
| } |
| } |
| |
| if (InVal == 0) { |
| // Different unwind edges have different values. Create a new PHI node |
| // in LPad. |
| PHINode *NewPN = PHINode::Create(PN->getType(), std::distance(PB, PE), |
| PN->getName() + ".lpad", LPad); |
| // Add an entry for each unwind edge, using the value from the old PHI. |
| for (pred_iterator PI = PB; PI != PE; ++PI) |
| NewPN->addIncoming(PN->getIncomingValueForBlock(*PI), *PI); |
| |
| // Now use this new PHI as the common incoming value for LPad in PN. |
| InVal = NewPN; |
| } |
| |
| // Revector exactly one entry in the PHI node to come from LPad and |
| // delete the entries that came from the invoke unwind edges. |
| for (pred_iterator PI = PB; PI != PE; ++PI) |
| PN->removeIncomingValue(*PI); |
| PN->addIncoming(InVal, LPad); |
| } |
| |
| // Add a fallthrough from LPad to the original landing pad. |
| BranchInst::Create(PostPad, LPad); |
| } |
| |
| // Create the landing pad instruction for each exception handling region at |
| // the start of the corresponding landing pad. At this point each exception |
| // handling region has its own landing pad, which is only reachable via the |
| // unwind edges of the region's invokes. |
| Type *UnwindDataTy = |
| StructType::get(Builder.getInt8PtrTy(), Builder.getInt32Ty(), NULL); |
| for (unsigned LPadNo = 1; LPadNo < NormalInvokes.size(); ++LPadNo) { |
| // Get the list of invokes for this GCC landing pad. |
| SmallVector<InvokeInst *, 8> &InvokesForPad = NormalInvokes[LPadNo]; |
| |
| if (InvokesForPad.empty()) |
| continue; |
| |
| // All of the invokes unwind to the the landing pad. |
| BasicBlock *LPad = InvokesForPad[0]->getUnwindDest(); |
| |
| // The exception handling region this landing pad is for. |
| eh_region region = get_eh_region_from_lp_number(LPadNo); |
| assert(region->index > 0 && "Invalid landing pad region!"); |
| unsigned RegionNo = region->index; |
| |
| // Insert instructions at the start of the landing pad, but after any phis. |
| Builder.SetInsertPoint(LPad, LPad->getFirstNonPHI()); |
| |
| // Create the landingpad instruction without any clauses. Clauses are added |
| // below. |
| tree personality = DECL_FUNCTION_PERSONALITY(FnDecl); |
| if (!personality) { |
| assert(function_needs_eh_personality(cfun) == eh_personality_any && |
| "No exception handling personality!"); |
| personality = lang_hooks.eh_personality(); |
| } |
| LandingPadInst *LPadInst = Builder.CreateLandingPad( |
| UnwindDataTy, DECL_LLVM(personality), 0, "exc"); |
| |
| // Store the exception pointer if made use of elsewhere. |
| if (RegionNo < ExceptionPtrs.size() && ExceptionPtrs[RegionNo]) { |
| Value *ExcPtr = Builder.CreateExtractValue(LPadInst, 0, "exc_ptr"); |
| Builder.CreateStore(ExcPtr, ExceptionPtrs[RegionNo]); |
| } |
| |
| // Store the selector value if made use of elsewhere. |
| if (RegionNo < ExceptionFilters.size() && ExceptionFilters[RegionNo]) { |
| Value *Filter = Builder.CreateExtractValue(LPadInst, 1, "filter"); |
| Builder.CreateStore(Filter, ExceptionFilters[RegionNo]); |
| } |
| |
| // Add clauses to the landing pad instruction. |
| bool AllCaught = false; // Did we see a catch-all or no-throw? |
| SmallSet<Constant *, 8> AlreadyCaught; // Typeinfos known caught already. |
| for (; region && !AllCaught; region = region->outer) |
| switch (region->type) { |
| case ERT_ALLOWED_EXCEPTIONS: { |
| // Filter. Compute the list of type infos. |
| AllCaught = true; |
| std::vector<Constant *> TypeInfos; |
| for (tree type = region->u.allowed.type_list; type; |
| type = TREE_CHAIN(type)) { |
| Constant *TypeInfo = ConvertTypeInfo(TREE_VALUE(type)); |
| // No point in letting a typeinfo through if we know it can't reach |
| // the filter in the first place. |
| if (AlreadyCaught.count(TypeInfo)) |
| continue; |
| TypeInfo = TheFolder->CreateBitCast(TypeInfo, Builder.getInt8PtrTy()); |
| TypeInfos.push_back(TypeInfo); |
| AllCaught = false; |
| } |
| |
| // Add the list of typeinfos as a filter clause. |
| ArrayType *FilterTy = |
| ArrayType::get(Builder.getInt8PtrTy(), TypeInfos.size()); |
| LPadInst->addClause(ConstantArray::get(FilterTy, TypeInfos)); |
| break; |
| } |
| case ERT_CLEANUP: |
| LPadInst->setCleanup(true); |
| break; |
| case ERT_MUST_NOT_THROW: { |
| // Same as a zero-length filter: add an empty filter clause. |
| ArrayType *FilterTy = ArrayType::get(Builder.getInt8PtrTy(), 0); |
| LPadInst->addClause( |
| ConstantArray::get(FilterTy, ArrayRef<Constant *>())); |
| AllCaught = true; |
| break; |
| } |
| case ERT_TRY: |
| // Catches. |
| for (eh_catch c = region->u.eh_try.first_catch; c; c = c->next_catch) |
| if (!c->type_list) { |
| // Catch-all - add a null pointer as a catch clause. |
| LPadInst->addClause(Constant::getNullValue(Builder.getInt8PtrTy())); |
| AllCaught = true; |
| break; |
| } else { |
| // Add the type infos. |
| for (tree type = c->type_list; type; type = TREE_CHAIN(type)) { |
| Constant *TypeInfo = ConvertTypeInfo(TREE_VALUE(type)); |
| // No point in trying to catch a typeinfo that was already caught. |
| if (!AlreadyCaught.insert(TypeInfo)) |
| continue; |
| LPadInst->addClause(TypeInfo); |
| } |
| } |
| break; |
| } |
| } |
| |
| NormalInvokes.clear(); |
| } |
| |
| /// EmitFailureBlocks - Emit the blocks containing failure code executed when |
| /// an exception is thrown in a must-not-throw region. |
| void TreeToLLVM::EmitFailureBlocks() { |
| for (unsigned RegionNo = 1; RegionNo < FailureBlocks.size(); ++RegionNo) { |
| BasicBlock *FailureBlock = FailureBlocks[RegionNo]; |
| |
| if (!FailureBlock) |
| continue; |
| |
| eh_region region = get_eh_region_from_number(RegionNo); |
| assert(region->type == ERT_MUST_NOT_THROW && "Unexpected region type!"); |
| |
| // Check whether all predecessors are invokes or not. Nothing exotic can |
| // occur here, only direct branches and unwinding via an invoke. |
| bool hasBranchPred = false; |
| bool hasInvokePred = false; |
| for (pred_iterator I = pred_begin(FailureBlock), E = pred_end(FailureBlock); |
| I != E && (!hasInvokePred || !hasBranchPred); ++I) { |
| TerminatorInst *T = (*I)->getTerminator(); |
| if (isa<InvokeInst>(T)) { |
| assert(FailureBlock != T->getSuccessor(0) && "Expected unwind target!"); |
| hasInvokePred = true; |
| } else { |
| assert(isa<BranchInst>(T) && "Wrong kind of failure predecessor!"); |
| hasBranchPred = true; |
| } |
| } |
| assert((hasBranchPred || hasInvokePred) && "No predecessors!"); |
| |
| // Determine the landing pad that invokes will unwind to. If there are no |
| // invokes, then there is no landing pad. |
| BasicBlock *LandingPad = NULL; |
| if (hasInvokePred) { |
| // If all predecessors are invokes, then the failure block can be used as |
| // the landing pad. Otherwise, create a landing pad. |
| if (hasBranchPred) |
| LandingPad = BasicBlock::Create(Context, "pad"); |
| else |
| LandingPad = FailureBlock; |
| } |
| |
| if (LandingPad) { |
| BeginBlock(LandingPad); |
| |
| // Generate a landingpad instruction with an empty (i.e. catch-all) filter |
| // clause. |
| Type *UnwindDataTy = |
| StructType::get(Builder.getInt8PtrTy(), Builder.getInt32Ty(), NULL); |
| tree personality = DECL_FUNCTION_PERSONALITY(FnDecl); |
| assert(personality && "No-throw region but no personality function!"); |
| LandingPadInst *LPadInst = Builder.CreateLandingPad( |
| UnwindDataTy, DECL_LLVM(personality), 1, "exc"); |
| ArrayType *FilterTy = ArrayType::get(Builder.getInt8PtrTy(), 0); |
| LPadInst->addClause(ConstantArray::get(FilterTy, ArrayRef<Constant *>())); |
| |
| if (LandingPad != FailureBlock) { |
| // Make sure all invokes unwind to the new landing pad. |
| for (pred_iterator I = pred_begin(FailureBlock), |
| E = pred_end(FailureBlock); |
| I != E;) { |
| TerminatorInst *T = (*I++)->getTerminator(); |
| if (isa<InvokeInst>(T)) |
| T->setSuccessor(1, LandingPad); |
| } |
| |
| // Branch to the failure block at the end of the landing pad. |
| Builder.CreateBr(FailureBlock); |
| } |
| } |
| |
| if (LandingPad != FailureBlock) |
| BeginBlock(FailureBlock); |
| |
| // Determine the failure function to call. |
| Value *FailFunc = DECL_LLVM(region->u.must_not_throw.failure_decl); |
| |
| // Make sure it has the right type. |
| FunctionType *FTy = FunctionType::get(Type::getVoidTy(Context), false); |
| FailFunc = Builder.CreateBitCast(FailFunc, FTy->getPointerTo()); |
| |
| // Spank the user for being naughty. |
| // TODO: Set the correct debug location. |
| CallInst *FailCall = Builder.CreateCall(FailFunc); |
| |
| // This is always fatal. |
| FailCall->setDoesNotReturn(); |
| FailCall->setDoesNotThrow(); |
| Builder.CreateUnreachable(); |
| } |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // ... Expressions ... |
| //===----------------------------------------------------------------------===// |
| |
| static bool canEmitRegisterVariable(tree exp) { |
| // Only variables can be marked as 'register'. |
| if (!isa<VAR_DECL>(exp) || !DECL_REGISTER(exp)) |
| return false; |
| |
| // We can emit inline assembler for access to global register variables. |
| if (TREE_STATIC(exp) || DECL_EXTERNAL(exp) || TREE_PUBLIC(exp)) |
| return true; |
| |
| // Emit inline asm if this is local variable with assembler name on it. |
| if (DECL_ASSEMBLER_NAME_SET_P(exp)) |
| return true; |
| |
| // Otherwise - it's normal automatic variable. |
| return false; |
| } |
| |
| /// EmitLoadOfLValue - When an l-value expression is used in a context that |
| /// requires an r-value, this method emits the lvalue computation, then loads |
| /// the result. |
| Value *TreeToLLVM::EmitLoadOfLValue(tree exp) { |
| if (canEmitRegisterVariable(exp)) |
| // If this is a register variable, EmitLV can't handle it (there is no |
| // l-value of a register variable). Emit an inline asm node that copies the |
| // value out of the specified register. |
| return EmitReadOfRegisterVariable(exp); |
| |
| LValue LV = EmitLV(exp); |
| LV.Volatile = TREE_THIS_VOLATILE(exp); |
| // TODO: Arrange for Volatile to already be set in the LValue. |
| unsigned Alignment = LV.getAlignment(); |
| |
| tree type = TREE_TYPE(exp); |
| if (!LV.isBitfield()) |
| // Scalar value: emit a load. |
| return LoadRegisterFromMemory(LV, type, describeAliasSet(exp), Builder); |
| |
| // This is a bitfield reference. |
| Type *Ty = getRegType(type); |
| if (!LV.BitSize) |
| return Constant::getNullValue(Ty); |
| |
| // Load the minimum number of bytes that covers the field. |
| unsigned LoadSizeInBits = LV.BitStart + LV.BitSize; |
| LoadSizeInBits = RoundUpToAlignment(LoadSizeInBits, BITS_PER_UNIT); |
| Type *LoadType = IntegerType::get(Context, LoadSizeInBits); |
| |
| // Load the bits. |
| Value *Ptr = Builder.CreateBitCast(LV.Ptr, LoadType->getPointerTo()); |
| Value *Val = Builder.CreateAlignedLoad(Ptr, Alignment, LV.Volatile); |
| |
| // Mask the bits out by shifting left first, then shifting right. The |
| // optimizers will turn this into an "and" in the unsigned case. |
| |
| // Shift the sign bit of the bitfield to the sign bit position in the loaded |
| // type. This zaps any extra bits occurring after the end of the bitfield. |
| unsigned FirstBitInVal = |
| BYTES_BIG_ENDIAN ? LoadSizeInBits - LV.BitStart - LV.BitSize |
| : LV.BitStart; |
| if (FirstBitInVal + LV.BitSize != LoadSizeInBits) { |
| Value *ShAmt = ConstantInt::get(LoadType, LoadSizeInBits - |
| (FirstBitInVal + LV.BitSize)); |
| Val = Builder.CreateShl(Val, ShAmt); |
| } |
| // Shift the first bit of the bitfield to be bit zero. This zaps any extra |
| // bits that occurred before the start of the bitfield. In the signed case |
| // this also duplicates the sign bit, giving a sign extended value. |
| bool isSigned = !TYPE_UNSIGNED(type); |
| Value *ShAmt = ConstantInt::get(LoadType, LoadSizeInBits - LV.BitSize); |
| Val = isSigned ? Builder.CreateAShr(Val, ShAmt) |
| : Builder.CreateLShr(Val, ShAmt); |
| |
| // Get the bits as an integer with the same in-memory size as the result. |
| // Extending the integer with defined bits (rather than storing it as is to |
| // the temporary, which in effect extends with undefined bits) is required |
| // in order to get the right result for C-like languages. |
| unsigned MemSize = GET_MODE_BITSIZE(TYPE_MODE(type)); |
| Type *ResIntTy = IntegerType::get(Context, MemSize); |
| Value *ResInt = Builder.CreateIntCast(Val, ResIntTy, isSigned); |
| |
| // Create the temporary, an integer. Ensure it is sufficiently aligned for |
| // both the integer and the real type. Store the bits to it. |
| Alignment = std::max(TYPE_ALIGN(type) / 8, |
| DL.getPrefTypeAlignment(ResIntTy)); |
| MemRef Tmp(CreateTemporary(ResIntTy, Alignment), Alignment, false); |
| Builder.CreateStore(ResInt, Tmp.Ptr); |
| |
| // At this point we have in essence just displaced the original set of bits to |
| // a new memory location that is byte aligned, from which we now trivially load |
| // the desired value. |
| return LoadRegisterFromMemory(Tmp, type, 0, Builder); |
| } |
| |
| Value *TreeToLLVM::EmitADDR_EXPR(tree exp) { |
| LValue LV = EmitLV(TREE_OPERAND(exp, 0)); |
| assert((!LV.isBitfield() || LV.BitStart == 0) && |
| "It is illegal to take the address of a bitfield!"); |
| // Perform a cast here if necessary. For example, GCC sometimes forms an |
| // ADDR_EXPR where the operand is an array, and the ADDR_EXPR type is a |
| // pointer to the first element. |
| return Builder.CreateBitCast(LV.Ptr, getRegType(TREE_TYPE(exp))); |
| } |
| |
| #if (GCC_MINOR < 7) |
| Value *TreeToLLVM::EmitCondExpr(tree exp) { |
| return TriviallyTypeConvert( |
| EmitReg_CondExpr(TREE_OPERAND(exp, 0), TREE_OPERAND(exp, 1), |
| TREE_OPERAND(exp, 2)), |
| getRegType(TREE_TYPE(exp))); |
| } |
| #endif |
| |
| Value *TreeToLLVM::EmitOBJ_TYPE_REF(tree exp) { |
| return Builder.CreateBitCast(EmitRegister(OBJ_TYPE_REF_EXPR(exp)), |
| getRegType(TREE_TYPE(exp))); |
| } |
| |
| #if (GCC_MINOR < 8) |
| INSTANTIATE_VECTOR(constructor_elt); |
| #endif |
| |
| /// EmitCONSTRUCTOR - emit the constructor into the location specified by |
| /// DestLoc. |
| Value *TreeToLLVM::EmitCONSTRUCTOR(tree exp, const MemRef *DestLoc) { |
| tree type = TREE_TYPE(exp); |
| Type *Ty = ConvertType(type); |
| if (VectorType *VTy = llvm::dyn_cast<VectorType>(Ty)) { |
| assert(DestLoc == 0 && "Dest location for vector value?"); |
| std::vector<Value *> BuildVecOps; |
| BuildVecOps.reserve(VTy->getNumElements()); |
| |
| // Insert all of the elements here. |
| unsigned HOST_WIDE_INT idx; |
| tree value; |
| FOR_EACH_CONSTRUCTOR_VALUE(CONSTRUCTOR_ELTS(exp), idx, value) { |
| Value *Elt = EmitRegister(value); |
| |
| if (VectorType *EltTy = llvm::dyn_cast<VectorType>(Elt->getType())) { |
| // GCC allows vectors to be built up from vectors. Extract all of the |
| // vector elements and add them to the list of build vector operands. |
| for (unsigned i = 0, e = EltTy->getNumElements(); i != e; ++i) { |
| Value *Index = Builder.getInt32(i); |
| BuildVecOps.push_back(Builder.CreateExtractElement(Elt, Index)); |
| } |
| } else { |
| assert(Elt->getType() == VTy->getElementType() && |
| "Unexpected type for vector constructor!"); |
| BuildVecOps.push_back(Elt); |
| } |
| } |
| |
| // Insert zero for any unspecified values. |
| while (BuildVecOps.size() < VTy->getNumElements()) |
| BuildVecOps.push_back(Constant::getNullValue(VTy->getElementType())); |
| assert(BuildVecOps.size() == VTy->getNumElements() && |
| "Vector constructor specified too many values!"); |
| |
| return BuildVector(BuildVecOps); |
| } |
| |
| assert(isa<AGGREGATE_TYPE>(type) && "Constructor for scalar type??"); |
| |
| // Start out with the value zero'd out. |
| EmitAggregateZero(*DestLoc, type); |
| |
| if (!CONSTRUCTOR_ELTS(exp)) |
| return 0; // No elements. |
| |
| const vec<constructor_elt, va_gc> &elt = *CONSTRUCTOR_ELTS(exp); |
| |
| if (elt.is_empty()) |
| return 0; // No elements. |
| |
| switch (TREE_CODE(TREE_TYPE(exp))) { |
| case ARRAY_TYPE: |
| case RECORD_TYPE: |
| default: |
| debug_tree(exp); |
| llvm_unreachable("We don't handle elements yet!"); |
| case QUAL_UNION_TYPE: |
| case UNION_TYPE: |
| // Store each element of the constructor into the corresponding field of |
| // DEST. |
| assert(elt.length() == 1 && "Union CONSTRUCTOR should have one element!"); |
| tree tree_purpose = elt[0].index; |
| tree tree_value = elt[0].value; |
| if (!tree_purpose) |
| return 0; // Not actually initialized? |
| |
| if (isa<AGGREGATE_TYPE>(TREE_TYPE(tree_purpose))) { |
| EmitAggregate(tree_value, *DestLoc); |
| } else { |
| // Scalar value. Evaluate to a register, then do the store. |
| Value *V = EmitRegister(tree_value); |
| StoreRegisterToMemory(V, *DestLoc, TREE_TYPE(tree_purpose), 0, Builder); |
| } |
| break; |
| } |
| return 0; |
| } |
| |
| /// llvm_load_scalar_argument - Load value located at LOC. |
| static Value *llvm_load_scalar_argument( |
| Value *L, llvm::Type *LLVMTy, unsigned RealSize, LLVMBuilder &Builder) { |
| if (!RealSize) |
| return UndefValue::get(LLVMTy); |
| |
| // Not clear what this is supposed to do on big endian machines... |
| assert(!BYTES_BIG_ENDIAN && "Unsupported case - please report"); |
| assert(LLVMTy->isIntegerTy() && "Expected an integer value!"); |
| Type *LoadType = IntegerType::get(Context, RealSize * 8); |
| L = Builder.CreateBitCast(L, LoadType->getPointerTo()); |
| Value *Val = Builder.CreateLoad(L); |
| if (LoadType->getPrimitiveSizeInBits() >= LLVMTy->getPrimitiveSizeInBits()) |
| Val = Builder.CreateTrunc(Val, LLVMTy); |
| else |
| Val = Builder.CreateZExt(Val, LLVMTy); |
| return Val; |
| } |
| |
| #ifndef LLVM_LOAD_SCALAR_ARGUMENT |
| #define LLVM_LOAD_SCALAR_ARGUMENT(LOC, TY, SIZE, BUILDER) \ |
| llvm_load_scalar_argument((LOC), (TY), (SIZE), (BUILDER)) |
| #endif |
| |
| namespace { |
| /// FunctionCallArgumentConversion - This helper class is driven by the ABI |
| /// definition for this target to figure out how to pass arguments into the |
| /// stack/regs for a function call. |
| struct FunctionCallArgumentConversion : public DefaultABIClient { |
| SmallVector<Value *, 16> &CallOperands; |
| SmallVector<Value *, 2> LocStack; |
| FunctionType *FTy; |
| const MemRef *DestLoc; |
| LLVMBuilder &Builder; |
| Value *TheValue; |
| MemRef RetBuf; |
| CallingConv::ID &CallingConv; |
| unsigned Offset; |
| bool isShadowRet; |
| bool isAggrRet; |
| bool useReturnSlot; |
| |
| FunctionCallArgumentConversion( |
| SmallVector<Value *, 16> &ops, FunctionType *FnTy, const MemRef *destloc, |
| bool ReturnSlotOpt, LLVMBuilder &b, CallingConv::ID &CC) |
| : CallOperands(ops), FTy(FnTy), DestLoc(destloc), Builder(b), |
| CallingConv(CC), Offset(0), isShadowRet(false), isAggrRet(false), |
| useReturnSlot(ReturnSlotOpt) {} |
| |
| /// getCallingConv - This provides the desired CallingConv for the function. |
| CallingConv::ID getCallingConv(void) { return CallingConv; } |
| |
| // Push the address of an argument. |
| void pushAddress(Value *Loc) { |
| assert(Loc && "Invalid location!"); |
| LocStack.push_back(Loc); |
| } |
| |
| // Push the value of an argument. |
| void pushValue(Value *V) { |
| assert(LocStack.empty() && "Value only allowed at top level!"); |
| LocStack.push_back(NULL); |
| TheValue = V; |
| } |
| |
| // Get the address of the current location. |
| Value *getAddress(void) { |
| assert(!LocStack.empty()); |
| Value *&Loc = LocStack.back(); |
| if (!Loc) { |
| // A value. Store to a temporary, and return the temporary's address. |
| // Any future access to this argument will reuse the same address. |
| Loc = TheTreeToLLVM->CreateTemporary(TheValue->getType()); |
| Builder.CreateStore(TheValue, Loc); |
| } |
| return Loc; |
| } |
| |
| // Get the value of the current location (of type Ty). |
| Value *getValue(Type *Ty) { |
| assert(!LocStack.empty()); |
| Value *Loc = LocStack.back(); |
| if (Loc) { |
| // An address. Convert to the right type and load the value out. |
| Loc = Builder.CreateBitCast(Loc, Ty->getPointerTo()); |
| // FIXME: Pass alignment information down rather than just using 1 here. |
| return Builder.CreateAlignedLoad(Loc, 1, "val"); |
| } else { |
| // A value - just return it. |
| assert(TheValue->getType() == Ty && "Value not of expected type!"); |
| return TheValue; |
| } |
| } |
| |
| void clear() { |
| assert(LocStack.size() == 1 && "Imbalance!"); |
| LocStack.clear(); |
| } |
| |
| bool isShadowReturn() const { return isShadowRet; } |
| bool isAggrReturn() { return isAggrRet; } |
| |
| // EmitShadowResult - If the return result was redirected to a buffer, |
| // emit it now. |
| Value *EmitShadowResult(tree type, const MemRef *DstLoc) { |
| if (!RetBuf.Ptr) |
| return 0; |
| |
| if (DstLoc) { |
| // Copy out the aggregate return value now. |
| assert(ConvertType(type) == |
| cast<PointerType>(RetBuf.Ptr->getType())->getElementType() && |
| "Inconsistent result types!"); |
| TheTreeToLLVM->EmitAggregateCopy(*DstLoc, RetBuf, type); |
| return 0; |
| } else { |
| // Read out the scalar return value now. |
| return Builder.CreateLoad(RetBuf.Ptr, "result"); |
| } |
| } |
| |
| /// HandleScalarResult - This callback is invoked if the function returns a |
| /// simple scalar result value. |
| void HandleScalarResult(Type */*RetTy*/) { |
| // There is nothing to do here if we return a scalar or void. |
| assert(DestLoc == 0 && |
| "Call returns a scalar but caller expects aggregate!"); |
| } |
| |
| /// HandleAggregateResultAsScalar - This callback is invoked if the function |
| /// returns an aggregate value by bit converting it to the specified scalar |
| /// type and returning that. |
| void HandleAggregateResultAsScalar(Type */*ScalarTy*/, unsigned Off = 0) { |
| this->Offset = Off; |
| } |
| |
| /// HandleAggregateResultAsAggregate - This callback is invoked if the |
| /// function returns an aggregate value using multiple return values. |
| void HandleAggregateResultAsAggregate(Type */*AggrTy*/) { |
| // There is nothing to do here. |
| isAggrRet = true; |
| } |
| |
| /// HandleAggregateShadowResult - This callback is invoked if the function |
| /// returns an aggregate value by using a "shadow" first parameter. If |
| /// RetPtr is set to true, the pointer argument itself is returned from the |
| /// function. |
| void HandleAggregateShadowResult(PointerType *PtrArgTy, bool /*RetPtr*/) { |
| // We need to pass memory to write the return value into. |
| // FIXME: alignment and volatility are being ignored! |
| assert(!DestLoc || PtrArgTy == DestLoc->Ptr->getType()); |
| |
| if (DestLoc == 0) { |
| // The result is unused, but still needs to be stored somewhere. |
| Value *Buf = TheTreeToLLVM->CreateTemporary(PtrArgTy->getElementType()); |
| CallOperands.push_back(Buf); |
| } else if (useReturnSlot) { |
| // Letting the call write directly to the final destination is safe and |
| // may be required. Do not use a buffer. |
| CallOperands.push_back(DestLoc->Ptr); |
| } else { |
| // Letting the call write directly to the final destination may not be |
| // safe (eg: if DestLoc aliases a parameter) and is not required - pass |
| // a buffer and copy it to DestLoc after the call. |
| RetBuf = TheTreeToLLVM->CreateTempLoc(PtrArgTy->getElementType()); |
| CallOperands.push_back(RetBuf.Ptr); |
| } |
| |
| // Note the use of a shadow argument. |
| isShadowRet = true; |
| } |
| |
| void HandlePad(llvm::Type *LLVMTy) { |
| CallOperands.push_back(UndefValue::get(LLVMTy)); |
| } |
| |
| /// HandleScalarShadowResult - This callback is invoked if the function |
| /// returns a scalar value by using a "shadow" first parameter, which is a |
| /// pointer to the scalar, of type PtrArgTy. If RetPtr is set to true, |
| /// the pointer argument itself is returned from the function. |
| void HandleScalarShadowResult(PointerType *PtrArgTy, bool /*RetPtr*/) { |
| assert(DestLoc == 0 && |
| "Call returns a scalar but caller expects aggregate!"); |
| // Create a buffer to hold the result. The result will be loaded out of |
| // it after the call. |
| RetBuf = TheTreeToLLVM->CreateTempLoc(PtrArgTy->getElementType()); |
| CallOperands.push_back(RetBuf.Ptr); |
| |
| // Note the use of a shadow argument. |
| isShadowRet = true; |
| } |
| |
| /// HandleScalarArgument - This is the primary callback that specifies an |
| /// LLVM argument to pass. It is only used for first class types. |
| void HandleScalarArgument(llvm::Type *LLVMTy, tree type, |
| unsigned RealSize = 0) { |
| Value *Loc = NULL; |
| if (RealSize) { |
| Value *L = getAddress(); |
| Loc = LLVM_LOAD_SCALAR_ARGUMENT(L, LLVMTy, RealSize, Builder); |
| } else |
| Loc = getValue(LLVMTy); |
| |
| // Perform any implicit type conversions. |
| if (CallOperands.size() < FTy->getNumParams()) { |
| Type *CalledTy = FTy->getParamType(CallOperands.size()); |
| if (Loc->getType() != CalledTy) { |
| if (type) { |
| bool isSigned = !TYPE_UNSIGNED(type); |
| Loc = TheTreeToLLVM->CastToAnyType(Loc, isSigned, CalledTy, false); |
| } else { |
| // Only trivial type conversions should get here. |
| Loc = Builder.CreateBitCast(Loc, CalledTy); |
| } |
| } |
| } |
| |
| CallOperands.push_back(Loc); |
| } |
| |
| /// HandleByInvisibleReferenceArgument - This callback is invoked if a |
| /// pointer (of type PtrTy) to the argument is passed rather than the |
| /// argument itself. |
| void HandleByInvisibleReferenceArgument(llvm::Type *PtrTy, tree /*type*/) { |
| Value *Loc = getAddress(); |
| Loc = Builder.CreateBitCast(Loc, PtrTy); |
| CallOperands.push_back(Loc); |
| } |
| |
| /// HandleByValArgument - This callback is invoked if the aggregate function |
| /// argument is passed by value. It is lowered to a parameter passed by |
| /// reference with an additional parameter attribute "ByVal". |
| void HandleByValArgument(llvm::Type *LLVMTy, tree /*type*/) { |
| Value *Loc = getAddress(); |
| assert(LLVMTy->getPointerTo() == Loc->getType()); |
| (void) LLVMTy; // Otherwise unused if asserts off - avoid compiler warning. |
| CallOperands.push_back(Loc); |
| } |
| |
| /// HandleFCAArgument - This callback is invoked if the aggregate function |
| /// argument is passed as a first class aggregate. |
| void HandleFCAArgument(llvm::Type *LLVMTy, tree /*type*/) { |
| Value *Loc = getAddress(); |
| assert(LLVMTy->getPointerTo() == Loc->getType()); |
| (void) LLVMTy; // Otherwise unused if asserts off - avoid compiler warning. |
| CallOperands.push_back(Builder.CreateLoad(Loc)); |
| } |
| |
| /// EnterField - Called when we're about the enter the field of a struct |
| /// or union. FieldNo is the number of the element we are entering in the |
| /// LLVM Struct, StructTy is the LLVM type of the struct we are entering. |
| void EnterField(unsigned FieldNo, llvm::Type *StructTy) { |
| Value *Loc = getAddress(); |
| Loc = Builder.CreateBitCast(Loc, StructTy->getPointerTo()); |
| pushAddress( |
| Builder.CreateStructGEP(Loc, FieldNo, flag_verbose_asm ? "elt" : "")); |
| } |
| void ExitField() { |
| assert(!LocStack.empty()); |
| LocStack.pop_back(); |
| } |
| }; |
| } |
| |
| /// EmitCallOf - Emit a call to the specified callee with the operands specified |
| /// in the GIMPLE_CALL 'stmt'. If the result of the call is a scalar, return the |
| /// result, otherwise store it in DestLoc. |
| Value *TreeToLLVM::EmitCallOf(Value *Callee, gimple stmt, const MemRef *DestLoc, |
| const AttributeSet &InPAL) { |
| BasicBlock *LandingPad = 0; // Non-zero indicates an invoke. |
| int LPadNo = 0; |
| |
| AttributeSet PAL = InPAL; |
| if (PAL.isEmpty() && isa<Function>(Callee)) |
| PAL = cast<Function>(Callee)->getAttributes(); |
| |
| // Work out whether to use an invoke or an ordinary call. |
| if (!stmt_could_throw_p(stmt)) |
| // This call does not throw - mark it 'nounwind'. |
| PAL = PAL.addAttribute(Callee->getContext(), AttributeSet::FunctionIndex, |
| Attribute::NoUnwind); |
| |
| if (!PAL.hasAttribute(AttributeSet::FunctionIndex, Attribute::NoUnwind)) { |
| // This call may throw. Determine if we need to generate |
| // an invoke rather than a simple call. |
| LPadNo = lookup_stmt_eh_lp(stmt); |
| |
| if (LPadNo > 0) { |
| // The call is in an exception handling region with a landing pad. |
| // Generate an invoke, with the GCC landing pad as the unwind destination. |
| // The destination may change to an LLVM only landing pad, which precedes |
| // the GCC one, after phi nodes have been populated (doing things this way |
| // simplifies the generation of phi nodes). |
| eh_landing_pad lp = get_eh_landing_pad_from_number(LPadNo); |
| assert(lp && "Post landing pad not found!"); |
| LandingPad = getLabelDeclBlock(lp->post_landing_pad); |
| } else if (LPadNo < 0) { |
| eh_region region = get_eh_region_from_lp_number(LPadNo); |
| // The call is in a must-not-throw region. Generate an invoke that causes |
| // the region's failure code to be run if an exception is thrown. |
| assert(region->type == ERT_MUST_NOT_THROW && "Unexpected region type!"); |
| |
| // Unwind to the block containing the failure code. |
| LandingPad = getFailureBlock(region->index); |
| } |
| } |
| |
| tree fndecl = gimple_call_fndecl(stmt); |
| #if (GCC_MINOR < 7) |
| tree fntype = |
| fndecl ? TREE_TYPE(fndecl) : TREE_TYPE(TREE_TYPE(gimple_call_fn(stmt))); |
| #else |
| tree fntype = gimple_call_fntype(stmt); |
| #endif |
| |
| // Determine the calling convention. |
| CallingConv::ID CallingConvention = CallingConv::C; |
| #ifdef TARGET_ADJUST_LLVM_CC |
| TARGET_ADJUST_LLVM_CC(CallingConvention, fntype); |
| #endif |
| |
| SmallVector<Value *, 16> CallOperands; |
| PointerType *PFTy = cast<PointerType>(Callee->getType()); |
| FunctionType *FTy = cast<FunctionType>(PFTy->getElementType()); |
| FunctionCallArgumentConversion Client(CallOperands, FTy, DestLoc, |
| gimple_call_return_slot_opt_p(stmt), |
| Builder, CallingConvention); |
| DefaultABI ABIConverter(Client); |
| |
| // Handle the result, including struct returns. |
| ABIConverter.HandleReturnType(gimple_call_return_type(stmt), |
| fndecl ? fndecl : fntype, |
| fndecl ? DECL_BUILT_IN(fndecl) : false); |
| |
| // Pass the static chain, if any, as the first parameter. |
| if (gimple_call_chain(stmt)) |
| CallOperands.push_back(EmitMemory(gimple_call_chain(stmt))); |
| |
| // Loop over the arguments, expanding them and adding them to the op list. |
| std::vector<Type *> ScalarArgs; |
| for (unsigned i = 0, e = gimple_call_num_args(stmt); i != e; ++i) { |
| tree arg = gimple_call_arg(stmt, i); |
| tree type = TREE_TYPE(arg); |
| Type *ArgTy = ConvertType(type); |
| |
| // Push the argument. |
| if (ArgTy->isSingleValueType()) { |
| // A scalar - push the value. |
| Client.pushValue(EmitMemory(arg)); |
| } else if (LLVM_SHOULD_PASS_AGGREGATE_AS_FCA(type, ArgTy)) { |
| if (isa<AGGREGATE_TYPE>(type)) { |
| // Pass the aggregate as a first class value. |
| LValue ArgVal = EmitLV(arg); |
| Client.pushValue(Builder.CreateLoad(ArgVal.Ptr)); |
| } else { |
| // Already first class (eg: a complex number) - push the value. |
| Client.pushValue(EmitMemory(arg)); |
| } |
| } else { |
| if (isa<AGGREGATE_TYPE>(type)) { |
| // An aggregate - push the address. |
| LValue ArgVal = EmitLV(arg); |
| assert(!ArgVal.isBitfield() && "Bitfields are first-class types!"); |
| Client.pushAddress(ArgVal.Ptr); |
| } else { |
| // A first class value (eg: a complex number). Push the address of a |
| // temporary copy. |
| MemRef Copy = CreateTempLoc(ArgTy); |
| StoreRegisterToMemory(EmitRegister(arg), Copy, type, 0, Builder); |
| Client.pushAddress(Copy.Ptr); |
| } |
| } |
| |
| AttrBuilder AttrBuilder; |
| |
| unsigned OldSize = CallOperands.size(); |
| |
| ABIConverter.HandleArgument(type, ScalarArgs, &AttrBuilder); |
| |
| if (AttrBuilder.hasAttributes()) { |
| // If the argument is split into multiple scalars, assign the |
| // attributes to all scalars of the aggregate. |
| for (unsigned j = OldSize + 1; j <= CallOperands.size(); ++j) |
| PAL = PAL.addAttributes(Context, j, |
| AttributeSet::get(Context, j, AttrBuilder)); |
| } |
| |
| Client.clear(); |
| } |
| |
| // If the caller and callee disagree about a parameter type but the difference |
| // is trivial, correct the type used by the caller. |
| for (unsigned i = 0, e = std::min((unsigned) CallOperands.size(), |
| FTy->getNumParams()); |
| i != e; ++i) { |
| Type *ExpectedTy = FTy->getParamType(i); |
| Type *ActualTy = CallOperands[i]->getType(); |
| if (ActualTy == ExpectedTy) |
| continue; |
| assert(isa<PointerType>(ActualTy) && isa<PointerType>(ExpectedTy) && |
| "Type difference is not trivial!"); |
| CallOperands[i] = Builder.CreateBitCast(CallOperands[i], ExpectedTy); |
| } |
| |
| // Unlike LLVM, GCC does not require that call statements provide a value for |
| // every function argument (it passes rubbish for arguments with no value). |
| // To get the same effect we pass 'undef' for any unspecified arguments. |
| if (CallOperands.size() < FTy->getNumParams()) |
| for (unsigned i = CallOperands.size(), e = FTy->getNumParams(); i != e; ++i) |
| CallOperands.push_back(UndefValue::get(FTy->getParamType(i))); |
| |
| Value *Call; |
| if (!LandingPad) { |
| Call = Builder.CreateCall(Callee, CallOperands); |
| cast<CallInst>(Call)->setCallingConv(CallingConvention); |
| cast<CallInst>(Call)->setAttributes(PAL); |
| } else { |
| BasicBlock *NextBlock = BasicBlock::Create(Context); |
| Call = Builder.CreateInvoke(Callee, NextBlock, LandingPad, CallOperands); |
| cast<InvokeInst>(Call)->setCallingConv(CallingConvention); |
| cast<InvokeInst>(Call)->setAttributes(PAL); |
| |
| if (LPadNo > 0) { |
| // The invoke's destination may change to an LLVM only landing pad, which |
| // precedes the GCC one, after phi nodes have been populated (doing things |
| // this way simplifies the generation of phi nodes). Record the invoke as |
| // well as the GCC exception handling region. |
| if ((unsigned) LPadNo >= NormalInvokes.size()) |
| NormalInvokes.resize(LPadNo + 1); |
| NormalInvokes[LPadNo].push_back(cast<InvokeInst>(Call)); |
| } |
| |
| BeginBlock(NextBlock); |
| } |
| |
| // If the call statement has void type then either the callee does not return |
| // a result, or it does but the result should be discarded. |
| if (isa<VOID_TYPE>(gimple_call_return_type(stmt))) |
| return 0; |
| |
| if (Client.isShadowReturn()) |
| return Client.EmitShadowResult(gimple_call_return_type(stmt), DestLoc); |
| |
| if (Client.isAggrReturn()) { |
| MemRef Target; |
| if (DestLoc) |
| Target = *DestLoc; |
| else |
| // Destination is a first class value (eg: a complex number). Extract to |
| // a temporary then load the value out later. |
| Target = CreateTempLoc(ConvertType(gimple_call_return_type(stmt))); |
| |
| if (DL.getTypeAllocSize(Call->getType()) <= |
| DL.getTypeAllocSize(cast<PointerType>(Target.Ptr->getType()) |
| ->getElementType())) { |
| Value *Dest = |
| Builder.CreateBitCast(Target.Ptr, Call->getType()->getPointerTo()); |
| LLVM_EXTRACT_MULTIPLE_RETURN_VALUE(Call, Dest, Target.Volatile, Builder); |
| } else { |
| // The call will return an aggregate value in registers, but |
| // those registers are bigger than Target. Allocate a |
| // temporary to match the registers, store the registers there, |
| // cast the temporary into the correct (smaller) type, and using |
| // the correct type, copy the value into Target. Assume the |
| // optimizer will delete the temporary and clean this up. |
| AllocaInst *biggerTmp = CreateTemporary(Call->getType()); |
| LLVM_EXTRACT_MULTIPLE_RETURN_VALUE(Call, biggerTmp, /*Volatile=*/ false, |
| Builder); |
| EmitAggregateCopy( |
| Target, MemRef(Builder.CreateBitCast(biggerTmp, |
| Call->getType()->getPointerTo()), |
| Target.getAlignment(), Target.Volatile), |
| gimple_call_return_type(stmt)); |
| } |
| |
| return DestLoc ? 0 : Builder.CreateLoad(Target.Ptr); |
| } |
| |
| if (!DestLoc) { |
| Type *RetTy = ConvertType(gimple_call_return_type(stmt)); |
| if (Call->getType() == RetTy) |
| return Call; // Normal scalar return. |
| |
| // May be something as simple as a float being returned as an integer, or |
| // something trickier like a complex int type { i32, i32 } being returned |
| // as an i64. |
| if (Call->getType()->canLosslesslyBitCastTo(RetTy)) |
| return Builder.CreateBitCast(Call, RetTy); // Simple case. |
| // Probably a scalar to complex conversion. |
| assert(DL.getTypeAllocSize(Call->getType()) == DL.getTypeAllocSize(RetTy) && |
| "Size mismatch in scalar to scalar conversion!"); |
| Value *Tmp = CreateTemporary(Call->getType()); |
| Builder.CreateStore(Call, Tmp); |
| return Builder.CreateLoad( |
| Builder.CreateBitCast(Tmp, RetTy->getPointerTo())); |
| } |
| |
| // If the caller expects an aggregate, we have a situation where the ABI for |
| // the current target specifies that the aggregate be returned in scalar |
| // registers even though it is an aggregate. We must bitconvert the scalar |
| // to the destination aggregate type. We do this by casting the DestLoc |
| // pointer and storing into it. The store does not necessarily start at the |
| // beginning of the aggregate (x86-64). |
| Value *Ptr = DestLoc->Ptr; |
| unsigned Align = DestLoc->getAlignment(); |
| // AggTy - The type of the aggregate being stored to. |
| Type *AggTy = cast<PointerType>(Ptr->getType())->getElementType(); |
| // MaxStoreSize - The maximum number of bytes we can store without overflowing |
| // the aggregate. |
| int64_t MaxStoreSize = DL.getTypeAllocSize(AggTy); |
| if (Client.Offset) { |
| Ptr = Builder.CreateBitCast(Ptr, Type::getInt8PtrTy(Context)); |
| Ptr = Builder.CreateGEP( |
| Ptr, ConstantInt::get(DL.getIntPtrType(Ptr->getType()), Client.Offset), |
| flag_verbose_asm ? "ro" : ""); |
| Align = MinAlign(Align, Client.Offset); |
| MaxStoreSize -= Client.Offset; |
| } |
| assert(MaxStoreSize > 0 && "Storing off end of aggregate?"); |
| Value *Val = Call; |
| // Check whether storing the scalar directly would overflow the aggregate. |
| if (DL.getTypeStoreSize(Call->getType()) > (uint64_t) MaxStoreSize) { |
| // Chop down the size of the scalar to the maximum number of bytes that can |
| // be stored without overflowing the destination. |
| // TODO: Check whether this works correctly on big-endian machines. |
| // Store the scalar to a temporary. |
| Value *Tmp = CreateTemporary(Call->getType()); |
| Builder.CreateStore(Call, Tmp); |
| // Load the desired number of bytes back out again as an integer of the |
| // appropriate size. |
| Type *SmallTy = IntegerType::get(Context, MaxStoreSize * 8); |
| Tmp = Builder.CreateBitCast(Tmp, PointerType::getUnqual(SmallTy)); |
| Val = Builder.CreateLoad(Tmp); |
| // Store the integer rather than the call result to the aggregate. |
| } |
| Ptr = Builder.CreateBitCast(Ptr, PointerType::getUnqual(Val->getType())); |
| Builder.CreateAlignedStore(Val, Ptr, Align, DestLoc->Volatile); |
| return 0; |
| } |
| |
| /// EmitSimpleCall - Emit a call to the function with the given name and return |
| /// type, passing the provided arguments (which should all be gimple registers |
| /// or local constants of register type). No marshalling is done: the arguments |
| /// are directly passed through. |
| CallInst *TreeToLLVM::EmitSimpleCall(StringRef CalleeName, tree ret_type, |
| /* arguments */ ...) { |
| va_list ops; |
| va_start(ops, ret_type); |
| |
| // Build the list of arguments. |
| std::vector<Value *> Args; |
| #ifdef TARGET_ADJUST_LLVM_CC |
| // Build the list of GCC argument types. |
| tree arg_types; |
| tree *chainp = &arg_types; |
| #endif |
| while (tree arg = va_arg(ops, tree)) { |
| Args.push_back(EmitRegister(arg)); |
| #ifdef TARGET_ADJUST_LLVM_CC |
| *chainp = build_tree_list(NULL, TREE_TYPE(arg)); |
| chainp = &TREE_CHAIN(*chainp); |
| #endif |
| } |
| #ifdef TARGET_ADJUST_LLVM_CC |
| // Indicate that this function is not varargs. |
| *chainp = void_list_node; |
| #endif |
| va_end(ops); |
| |
| Type *RetTy = isa<VOID_TYPE>(ret_type) ? Type::getVoidTy(Context) |
| : getRegType(ret_type); |
| |
| // The LLVM argument types. |
| std::vector<Type *> ArgTys; |
| ArgTys.reserve(Args.size()); |
| for (unsigned i = 0, e = Args.size(); i != e; ++i) |
| ArgTys.push_back(Args[i]->getType()); |
| |
| // Determine the calling convention. |
| CallingConv::ID CC = CallingConv::C; |
| #ifdef TARGET_ADJUST_LLVM_CC |
| // Query the target for the calling convention to use. |
| tree fntype = build_function_type(ret_type, arg_types); |
| TARGET_ADJUST_LLVM_CC(CC, fntype); |
| #endif |
| |
| // Get the function declaration for the callee. |
| FunctionType *FTy = FunctionType::get(RetTy, ArgTys, /*isVarArg*/ false); |
| Constant *Func = TheModule->getOrInsertFunction(CalleeName, FTy); |
| |
| // If the function already existed with the wrong prototype then don't try to |
| // muck with its calling convention. Otherwise, set the calling convention. |
| if (Function *F = llvm::dyn_cast<Function>(Func)) |
| F->setCallingConv(CC); |
| |
| // Finally, call the function. |
| CallInst *CI = Builder.CreateCall(Func, Args); |
| CI->setCallingConv(CC); |
| return CI; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // ... Inline Assembly and Register Variables ... |
| //===----------------------------------------------------------------------===// |
| |
| // LLVM_GET_REG_NAME - Default to use GCC's register names. Targets may |
| // override this to use different names for some registers. The REG_NAME is |
| // the name before it was decoded; it may be null in some contexts. |
| #ifndef LLVM_GET_REG_NAME |
| #define LLVM_GET_REG_NAME(REG_NAME, REG_NUM) reg_names[REG_NUM] |
| #endif |
| |
| // LLVM_CANONICAL_ADDRESS_CONSTRAINTS - GCC defines the "p" constraint to |
| // allow a valid memory address, but targets differ widely on what is allowed |
| // as an address. This macro is a string containing the canonical constraint |
| // characters that are conservatively valid addresses. Default to allowing an |
| // address in a register, since that works for many targets. |
| #ifndef LLVM_CANONICAL_ADDRESS_CONSTRAINTS |
| #define LLVM_CANONICAL_ADDRESS_CONSTRAINTS "r" |
| #endif |
| |
| /// Reads from register variables are handled by emitting an inline asm node |
| /// that copies the value out of the specified register. |
| Value *TreeToLLVM::EmitReadOfRegisterVariable(tree decl) { |
| Type *MemTy = ConvertType(TREE_TYPE(decl)); |
| Type *RegTy = getRegType(TREE_TYPE(decl)); |
| |
| // If there was an error, return something bogus. |
| if (ValidateRegisterVariable(decl)) |
| return UndefValue::get(RegTy); |
| |
| // Turn this into a 'tmp = call Ty asm "", "={reg}"()'. |
| FunctionType *FTy = FunctionType::get(MemTy, std::vector<Type *>(), false); |
| |
| const char *Name = extractRegisterName(decl); |
| Name = LLVM_GET_REG_NAME(Name, decode_reg_name(Name)); |
| |
| InlineAsm *IA = InlineAsm::get(FTy, "", "={" + std::string(Name) + "}", true); |
| CallInst *Call = Builder.CreateCall(IA); |
| Call->setDoesNotThrow(); |
| |
| // Convert the call result to in-register type. |
| return Mem2Reg(Call, TREE_TYPE(decl), Builder); |
| } |
| |
| /// Stores to register variables are handled by emitting an inline asm node |
| /// that copies the value into the specified register. |
| void TreeToLLVM::EmitModifyOfRegisterVariable(tree decl, Value *RHS) { |
| // If there was an error, bail out. |
| if (ValidateRegisterVariable(decl)) |
| return; |
| |
| // Convert to in-memory type. |
| RHS = Reg2Mem(RHS, TREE_TYPE(decl), Builder); |
| |
| // Turn this into a 'call void asm sideeffect "", "{reg}"(Ty %RHS)'. |
| std::vector<Type *> ArgTys; |
| ArgTys.push_back(RHS->getType()); |
| FunctionType *FTy = |
| FunctionType::get(Type::getVoidTy(Context), ArgTys, false); |
| |
| const char *Name = extractRegisterName(decl); |
| Name = LLVM_GET_REG_NAME(Name, decode_reg_name(Name)); |
| |
| InlineAsm *IA = InlineAsm::get(FTy, "", "{" + std::string(Name) + "}", true); |
| CallInst *Call = Builder.CreateCall(IA, RHS); |
| Call->setDoesNotThrow(); |
| } |
| |
| /// ConvertInlineAsmStr - Convert the specified inline asm string to an LLVM |
| /// InlineAsm string. The GNU style inline asm template string has the |
| /// following format: |
| /// %N (for N a digit) means print operand N in usual manner. |
| /// %= means a unique number for the inline asm. |
| /// %lN means require operand N to be a CODE_LABEL or LABEL_REF |
| /// and print the label name with no punctuation. |
| /// %cN means require operand N to be a constant |
| /// and print the constant expression with no punctuation. |
| /// %aN means expect operand N to be a memory address |
| /// (not a memory reference!) and print a reference to that address. |
| /// %nN means expect operand N to be a constant and print a constant |
| /// expression for minus the value of the operand, with no other |
| /// punctuation. |
| /// Other %xN expressions are turned into LLVM ${N:x} operands. |
| /// |
| static std::string ConvertInlineAsmStr(gimple stmt, unsigned NumOperands) { |
| const char *AsmStr = gimple_asm_string(stmt); |
| |
| // gimple_asm_input_p - This flag is set if this is a non-extended ASM, |
| // which means that the asm string should not be interpreted, other than |
| // to escape $'s. |
| if (gimple_asm_input_p(stmt)) { |
| const char *InStr = AsmStr; |
| std::string Result; |
| while (1) { |
| switch (*InStr++) { |
| case 0: |
| return Result; // End of string. |
| default: |
| Result += InStr[-1]; |
| break; // Normal character. |
| case '$': |
| Result += "$$"; |
| break; // Escape '$' characters. |
| } |
| } |
| } |
| |
| std::string Result; |
| while (1) { |
| switch (*AsmStr++) { |
| case 0: |
| return Result; // End of string. |
| default: |
| Result += AsmStr[-1]; |
| break; // Normal character. |
| case '$': |
| Result += "$$"; |
| break; // Escape '$' characters. |
| #ifdef ASSEMBLER_DIALECT |
| // Note that we can't escape to ${, because that is the syntax for vars. |
| case '{': |
| Result += "$("; |
| break; // Escape '{' character. |
| case '}': |
| Result += "$)"; |
| break; // Escape '}' character. |
| case '|': |
| Result += "$|"; |
| break; // Escape '|' character. |
| #endif |
| case '%': // GCC escape character. |
| char EscapedChar = *AsmStr++; |
| if (EscapedChar == '%') { // Escaped '%' character |
| Result += '%'; |
| } else if (EscapedChar == '=') { // Unique ID for the asm instance. |
| Result += "${:uid}"; |
| } |
| #ifdef LLVM_ASM_EXTENSIONS |
| LLVM_ASM_EXTENSIONS(EscapedChar, AsmStr, Result) |
| #endif |
| else if (ISALPHA(EscapedChar)) { |
| // % followed by a letter and some digits. This outputs an operand in a |
| // special way depending on the letter. We turn this into LLVM ${N:o} |
| // syntax. |
| char *EndPtr; |
| unsigned long OpNum = strtoul(AsmStr, &EndPtr, 10); |
| |
| if (AsmStr == EndPtr) { |
| error("operand number missing after %%-letter"); |
| return Result; |
| } else if (OpNum >= NumOperands) { |
| error("operand number out of range"); |
| return Result; |
| } |
| Result += "${" + utostr(OpNum) + ":" + EscapedChar + "}"; |
| AsmStr = EndPtr; |
| } |
| else if (ISDIGIT(EscapedChar)) { |
| char *EndPtr; |
| unsigned long OpNum = strtoul(AsmStr - 1, &EndPtr, 10); |
| AsmStr = EndPtr; |
| Result += "$" + utostr(OpNum); |
| #ifdef PRINT_OPERAND_PUNCT_VALID_P |
| } |
| else if (PRINT_OPERAND_PUNCT_VALID_P((unsigned char) EscapedChar)) { |
| Result += "${:"; |
| Result += EscapedChar; |
| Result += "}"; |
| #endif |
| } |
| else { |
| output_operand_lossage("invalid %%-code"); |
| } |
| break; |
| } |
| } |
| } |
| |
| /// isOperandMentioned - Return true if the given operand is explicitly |
| /// mentioned in the asm string. For example if passed operand 1 then |
| /// this routine checks that the asm string does not contain "%1". |
| static bool isOperandMentioned(gimple stmt, unsigned OpNum) { |
| // If this is a non-extended ASM then the contents of the asm string are not |
| // to be interpreted. |
| if (gimple_asm_input_p(stmt)) |
| return false; |
| // Search for a non-escaped '%' character followed by OpNum. |
| for (const char *AsmStr = gimple_asm_string(stmt); * AsmStr; ++AsmStr) { |
| if (*AsmStr != '%') |
| // Not a '%', move on to next character. |
| continue; |
| char Next = AsmStr[1]; |
| // If this is "%%" then the '%' is escaped - skip both '%' characters. |
| if (Next == '%') { |
| ++AsmStr; |
| continue; |
| } |
| // Whitespace is not allowed between the '%' and the number, so check that |
| // the next character is a digit. |
| if (!ISDIGIT(Next)) |
| continue; |
| char *EndPtr; |
| // If this is an explicit reference to OpNum then we are done. |
| if (OpNum == strtoul(AsmStr + 1, &EndPtr, 10)) |
| return true; |
| // Otherwise, skip over the number and keep scanning. |
| AsmStr = EndPtr - 1; |
| } |
| return false; |
| } |
| |
| /// CanonicalizeConstraint - If we can canonicalize the constraint into |
| /// something simpler, do so now. This turns register classes with a single |
| /// register into the register itself, expands builtin constraints to multiple |
| /// alternatives, etc. |
| static std::string CanonicalizeConstraint(const char *Constraint) { |
| std::string Result; |
| |
| // Skip over modifier characters. |
| bool DoneModifiers = false; |
| while (!DoneModifiers) { |
| switch (*Constraint) { |
| default: |
| DoneModifiers = true; |
| break; |
| case '=': |
| llvm_unreachable("Should be after '='s"); |
| case '+': |
| llvm_unreachable("'+' should already be expanded"); |
| case '*': |
| case '?': |
| case '!': |
| ++Constraint; |
| break; |
| case '&': // Pass earlyclobber to LLVM. |
| case '%': // Pass commutative to LLVM. |
| Result += *Constraint++; |
| break; |
| case '#': // No constraint letters left. |
| return Result; |
| } |
| } |
| |
| // If this constraint is multiple letters add a parsing helper prefix. |
| if (CONSTRAINT_LEN(*Constraint, Constraint) > 1) |
| Result += "^"; |
| |
| while (*Constraint) { |
| char ConstraintChar = *Constraint++; |
| |
| // 'g' is just short-hand for 'imr'. |
| if (ConstraintChar == 'g') { |
| Result += "imr"; |
| continue; |
| } |
| |
| // Translate 'p' to a target-specific set of constraints that |
| // conservatively allow a valid memory address. For inline assembly there |
| // is no way to know the mode of the data being addressed, so this is only |
| // a rough approximation of how GCC handles this constraint. |
| if (ConstraintChar == 'p') { |
| Result += LLVM_CANONICAL_ADDRESS_CONSTRAINTS; |
| continue; |
| } |
| |
| // See if this is a regclass constraint. |
| unsigned RegClass; |
| if (ConstraintChar == 'r') |
| // REG_CLASS_FROM_CONSTRAINT doesn't support 'r' for some reason. |
| RegClass = GENERAL_REGS; |
| else |
| RegClass = REG_CLASS_FROM_CONSTRAINT(Constraint[-1], Constraint - 1); |
| |
| if (RegClass == NO_REGS) { // not a reg class. |
| Result += ConstraintChar; |
| continue; |
| } |
| |
| // Look to see if the specified regclass has exactly one member, and if so, |
| // what it is. Cache this information in AnalyzedRegClasses once computed. |
| static std::map<unsigned, int> AnalyzedRegClasses; |
| |
| std::map<unsigned, int>::iterator I = |
| AnalyzedRegClasses.lower_bound(RegClass); |
| |
| int RegMember; |
| if (I != AnalyzedRegClasses.end() && I->first == RegClass) { |
| // We've already computed this, reuse value. |
| RegMember = I->second; |
| } else { |
| // Otherwise, scan the regclass, looking for exactly one member. |
| RegMember = -1; // -1 => not a single-register class. |
| for (unsigned j = 0; j != FIRST_PSEUDO_REGISTER; ++j) |
| if (TEST_HARD_REG_BIT(reg_class_contents[RegClass], j)) { |
| if (RegMember == -1) { |
| RegMember = j; |
| } else { |
| RegMember = -1; |
| break; |
| } |
| } |
| // Remember this answer for the next query of this regclass. |
| AnalyzedRegClasses.insert(I, std::make_pair(RegClass, RegMember)); |
| } |
| |
| // If we found a single register register class, return the register. |
| if (RegMember != -1) { |
| Result += '{'; |
| Result += LLVM_GET_REG_NAME(0, RegMember); |
| Result += '}'; |
| } else { |
| Result += ConstraintChar; |
| } |
| } |
| |
| return Result; |
| } |
| |
| /// See if operand "exp" can use the indicated Constraint (which is |
| /// terminated by a null or a comma). |
| /// Returns: -1=no, 0=yes but auxiliary instructions needed, 1=yes and free |
| static int MatchWeight(const char *Constraint, tree Operand) { |
| const char *p = Constraint; |
| int RetVal = 0; |
| // Look for hard register operand. This matches only a constraint of a |
| // register class that includes that hard register, and it matches that |
| // perfectly, so we never return 0 in this case. |
| if (isa<VAR_DECL>(Operand) && DECL_HARD_REGISTER(Operand)) { |
| int RegNum = decode_reg_name(extractRegisterName(Operand)); |
| RetVal = -1; |
| if (RegNum >= 0) { |
| do { |
| unsigned RegClass; |
| if (*p == 'r') |
| RegClass = GENERAL_REGS; |
| else |
| RegClass = REG_CLASS_FROM_CONSTRAINT(*p, p); |
| if (RegClass != NO_REGS && |
| TEST_HARD_REG_BIT(reg_class_contents[RegClass], RegNum)) { |
| RetVal = 1; |
| break; |
| } |
| ++p; |
| } while (*p != ',' && *p != 0); |
| } |
| } |
| // Look for integer constant operand. This cannot match "m", and "i" is |
| // better than "r". FIXME target-dependent immediate letters are not handled |
| // yet; in general they require looking at the value. |
| if (isa<INTEGER_CST>(Operand)) { |
| do { |
| RetVal = -1; |
| if (*p == 'i' || *p == 'n') { // integer constant |
| RetVal = 1; |
| break; |
| } |
| if (*p != 'm' && *p != 'o' && *p != 'V') // not memory |
| RetVal = 0; |
| ++p; |
| } while (*p != ',' && *p != 0); |
| } |
| /// TEMPORARY. This has the effect that alternative 0 is always chosen, |
| /// except in the cases handled above. |
| return RetVal; |
| } |
| |
| /// ChooseConstraintTuple: we know each of the NumInputs+NumOutputs strings |
| /// in Constraints[] is a comma-separated list of NumChoices different |
| /// constraints. Look through the operands and constraint possibilities |
| /// and pick a tuple where all the operands match. Replace the strings |
| /// in Constraints[] with the shorter strings from that tuple (malloc'ed, |
| /// caller is responsible for cleaning it up). Later processing can alter what |
| /// Constraints points to, so to make sure we delete everything, the addresses |
| /// of everything we allocated also are returned in StringStorage. |
| /// Casting back and forth from char* to const char* is Ugly, but we have to |
| /// interface with C code that expects const char*. |
| /// |
| /// gcc's algorithm for picking "the best" tuple is quite complicated, and |
| /// is performed after things like SROA, not before. At the moment we are |
| /// just trying to pick one that will work. This may get refined. |
| static void ChooseConstraintTuple(gimple stmt, const char **Constraints, |
| unsigned NumChoices, |
| BumpPtrAllocator &StringStorage) { |
| unsigned NumInputs = gimple_asm_ninputs(stmt); |
| unsigned NumOutputs = gimple_asm_noutputs(stmt); |
| |
| int MaxWeight = -1; |
| unsigned int CommasToSkip = 0; |
| int *Weights = (int *)alloca(NumChoices * sizeof(int)); |
| // RunningConstraints is pointers into the Constraints strings which |
| // are incremented as we go to point to the beginning of each |
| // comma-separated alternative. |
| const char **RunningConstraints = |
| (const char **)alloca((NumInputs + NumOutputs) * sizeof(const char *)); |
| memcpy(RunningConstraints, Constraints, |
| (NumInputs + NumOutputs) * sizeof(const char *)); |
| // The entire point of this loop is to compute CommasToSkip. |
| for (unsigned i = 0; i != NumChoices; ++i) { |
| Weights[i] = 0; |
| for (unsigned j = 0; j != NumOutputs; ++j) { |
| tree Output = gimple_asm_output_op(stmt, j); |
| if (i == 0) |
| RunningConstraints[j]++; // skip leading = |
| const char *p = RunningConstraints[j]; |
| while (*p == '*' || *p == '&' || *p == '%') // skip modifiers |
| p++; |
| if (Weights[i] != -1) { |
| int w = MatchWeight(p, TREE_VALUE(Output)); |
| // Nonmatch means the entire tuple doesn't match. However, we |
| // keep scanning to set up RunningConstraints correctly for the |
| // next tuple. |
| if (w < 0) |
| Weights[i] = -1; |
| else |
| Weights[i] += w; |
| } |
| while (*p != 0 && *p != ',') |
| p++; |
| if (*p != 0) { |
| p++; // skip comma |
| while (*p == '*' || *p == '&' || *p == '%') |
| p++; // skip modifiers |
| } |
| RunningConstraints[j] = p; |
| } |
| for (unsigned j = 0; j != NumInputs; ++j) { |
| tree Input = gimple_asm_input_op(stmt, j); |
| const char *p = RunningConstraints[NumOutputs + j]; |
| if (Weights[i] != -1) { |
| int w = MatchWeight(p, TREE_VALUE(Input)); |
| if (w < 0) |
| Weights[i] = -1; // As above. |
| else |
| Weights[i] += w; |
| } |
| while (*p != 0 && *p != ',') |
| p++; |
| if (*p != 0) |
| p++; |
| RunningConstraints[NumOutputs + j] = p; |
| } |
| if (Weights[i] > MaxWeight) { |
| CommasToSkip = i; |
| MaxWeight = Weights[i]; |
| } |
| } |
| // We have picked an alternative (the CommasToSkip'th one). |
| // Change Constraints to point to malloc'd copies of the appropriate |
| // constraints picked out of the original strings. |
| for (unsigned int i = 0; i < NumInputs + NumOutputs; i++) { |
| assert(*(RunningConstraints[i]) == 0); // sanity check |
| const char *start = Constraints[i]; |
| if (i < NumOutputs) |
| start++; // skip '=' or '+' |
| const char *end = start; |
| while (*end != ',' && *end != 0) |
| end++; |
| for (unsigned int j = 0; j < CommasToSkip; j++) { |
| start = end + 1; |
| end = start; |
| while (*end != ',' && *end != 0) |
| end++; |
| } |
| // String we want is at start..end-1 inclusive. |
| // For outputs, copy the leading = or +. |
| char *newstring; |
| if (i < NumOutputs) { |
| newstring = StringStorage.Allocate<char>(end - start + 1 + 1); |
| newstring[0] = *(Constraints[i]); |
| strncpy(newstring + 1, start, end - start); |
| newstring[end - start + 1] = 0; |
| } else { |
| newstring = StringStorage.Allocate<char>(end - start + 1); |
| strncpy(newstring, start, end - start); |
| newstring[end - start] = 0; |
| } |
| Constraints[i] = (const char *)newstring; |
| } |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // ... Helpers for Builtin Function Expansion ... |
| //===----------------------------------------------------------------------===// |
| |
| Value *TreeToLLVM::BuildVector(const std::vector<Value *> &Ops) { |
| assert((Ops.size() & (Ops.size() - 1)) == 0 && |
| "Not a power-of-two sized vector!"); |
| bool AllConstants = true; |
| for (unsigned i = 0, e = Ops.size(); i != e && AllConstants; ++i) |
| AllConstants &= isa<Constant>(Ops[i]); |
| |
| // If this is a constant vector, create a ConstantVector. |
| if (AllConstants) { |
| SmallVector<Constant *, 16> CstOps; |
| for (unsigned i = 0, e = Ops.size(); i != e; ++i) |
| CstOps.push_back(cast<Constant>(Ops[i])); |
| return ConstantVector::get(CstOps); |
| } |
| |
| // Otherwise, insertelement the values to build the vector. |
| Value *Result = |
| UndefValue::get(VectorType::get(Ops[0]->getType(), Ops.size())); |
| |
| for (unsigned i = 0, e = Ops.size(); i != e; ++i) |
| Result = Builder.CreateInsertElement(Result, Ops[i], Builder.getInt32(i)); |
| |
| return Result; |
| } |
| |
| /// BuildVector - This varargs function builds a literal vector ({} syntax) with |
| /// the specified null-terminated list of elements. The elements must be all |
| /// the same element type and there must be a power of two of them. |
| Value *TreeToLLVM::BuildVector(Value *Elt, ...) { |
| std::vector<Value *> Ops; |
| va_list VA; |
| va_start(VA, Elt); |
| |
| Ops.push_back(Elt); |
| while (Value *Arg = va_arg(VA, Value *)) |
| Ops.push_back(Arg); |
| va_end(VA); |
| |
| return BuildVector(Ops); |
| } |
| |
| /// BuildVectorShuffle - Given two vectors and a variable length list of int |
| /// constants, create a shuffle of the elements of the inputs, where each dest |
| /// is specified by the indexes. The int constant list must be as long as the |
| /// number of elements in the input vector. |
| /// |
| /// Undef values may be specified by passing in -1 as the result value. |
| /// |
| Value *TreeToLLVM::BuildVectorShuffle(Value *InVec1, Value *InVec2, ...) { |
| assert(InVec1->getType()->isVectorTy() && |
| InVec1->getType() == InVec2->getType() && "Invalid shuffle!"); |
| unsigned NumElements = cast<VectorType>(InVec1->getType())->getNumElements(); |
| |
| // Get all the indexes from varargs. |
| SmallVector<Constant *, 16> Idxs; |
| va_list VA; |
| va_start(VA, InVec2); |
| for (unsigned i = 0; i != NumElements; ++i) { |
| int idx = va_arg(VA, int); |
| if (idx == -1) |
| Idxs.push_back(UndefValue::get(Type::getInt32Ty(Context))); |
| else { |
| assert((unsigned) idx < 2 * NumElements && "Element index out of range!"); |
| Idxs.push_back(Builder.getInt32(idx)); |
| } |
| } |
| va_end(VA); |
| |
| // Turn this into the appropriate shuffle operation. |
| return Builder.CreateShuffleVector(InVec1, InVec2, ConstantVector::get(Idxs)); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // ... Builtin Function Expansion ... |
| //===----------------------------------------------------------------------===// |
| |
| /// EmitFrontendExpandedBuiltinCall - We allow the target to do some amount |
| /// of lowering. This allows us to avoid having intrinsics for operations that |
| /// directly correspond to LLVM constructs. |
| /// |
| /// This method returns true if the builtin is handled, otherwise false. |
| /// |
| bool TreeToLLVM::EmitFrontendExpandedBuiltinCall( |
| gimple stmt, tree fndecl, const MemRef *DestLoc, Value *&Result) { |
| #ifdef LLVM_TARGET_INTRINSIC_LOWER |
| // Get the result type and operand line in an easy to consume format. |
| Type *ResultType = ConvertType(TREE_TYPE(TREE_TYPE(fndecl))); |
| std::vector<Value *> Operands; |
| for (unsigned i = 0, e = gimple_call_num_args(stmt); i != e; ++i) { |
| tree OpVal = gimple_call_arg(stmt, i); |
| if (isa<AGGREGATE_TYPE>(TREE_TYPE(OpVal))) { |
| MemRef OpLoc = CreateTempLoc(ConvertType(TREE_TYPE(OpVal))); |
| EmitAggregate(OpVal, OpLoc); |
| Operands.push_back(Builder.CreateLoad(OpLoc.Ptr)); |
| } else { |
| Operands.push_back(EmitMemory(OpVal)); |
| } |
| } |
| |
| return LLVM_TARGET_INTRINSIC_LOWER(stmt, fndecl, DestLoc, Result, ResultType, |
| Operands); |
| #else |
| // Avoid compiler warnings about unused parameters. |
| (void) stmt; |
| (void) fndecl; |
| (void) DestLoc; |
| (void) Result; |
| return false; |
| #endif |
| } |
| |
| /// TargetBuiltinCache - A cache of builtin intrinsics indexed by the GCC |
| /// builtin number. |
| static std::vector<Constant *> TargetBuiltinCache; |
| |
| Value *TreeToLLVM::BuildBinaryAtomic(gimple stmt, AtomicRMWInst::BinOp Kind, |
| unsigned PostOp) { |
| tree return_type = gimple_call_return_type(stmt); |
| Type *ResultTy = ConvertType(return_type); |
| Value *C[2] = { EmitMemory(gimple_call_arg(stmt, 0)), |
| EmitMemory(gimple_call_arg(stmt, 1)) }; |
| Type *Ty[2]; |
| Ty[0] = ResultTy; |
| Ty[1] = ResultTy->getPointerTo(); |
| C[0] = Builder.CreateBitCast(C[0], Ty[1]); |
| C[1] = Builder.CreateIntCast( |
| C[1], Ty[0], /*isSigned*/ !TYPE_UNSIGNED(return_type), "cast"); |
| Value *Result = |
| Builder.CreateAtomicRMW(Kind, C[0], C[1], SequentiallyConsistent); |
| if (PostOp) |
| Result = Builder.CreateBinOp(Instruction::BinaryOps(PostOp), Result, C[1]); |
| |
| Result = Builder.CreateIntToPtr(Result, ResultTy); |
| return Result; |
| } |
| |
| Value * |
| TreeToLLVM::BuildCmpAndSwapAtomic(gimple stmt, unsigned Bits, bool isBool) { |
| tree ptr = gimple_call_arg(stmt, 0); |
| tree old_val = gimple_call_arg(stmt, 1); |
| tree new_val = gimple_call_arg(stmt, 2); |
| |
| // The type loaded from/stored to memory. |
| Type *MemTy = IntegerType::get(Context, Bits); |
| Type *MemPtrTy = MemTy->getPointerTo(); |
| |
| Value *Ptr = Builder.CreateBitCast(EmitRegister(ptr), MemPtrTy); |
| Value *Old_Val = |
| CastToAnyType(EmitRegister(old_val), !TYPE_UNSIGNED(TREE_TYPE(old_val)), |
| MemTy, !TYPE_UNSIGNED(TREE_TYPE(old_val))); |
| Value *New_Val = |
| CastToAnyType(EmitRegister(new_val), !TYPE_UNSIGNED(TREE_TYPE(new_val)), |
| MemTy, !TYPE_UNSIGNED(TREE_TYPE(new_val))); |
| |
| Value *C[3] = { Ptr, Old_Val, New_Val }; |
| Value *Result = |
| Builder.CreateAtomicCmpXchg(C[0], C[1], C[2], SequentiallyConsistent); |
| |
| if (isBool) |
| Result = Builder.CreateICmpEQ(Result, Old_Val); |
| tree return_type = gimple_call_return_type(stmt); |
| Result = CastToAnyType(Result, !TYPE_UNSIGNED(return_type), |
| getRegType(return_type), !TYPE_UNSIGNED(return_type)); |
| return Reg2Mem(Result, return_type, Builder); |
| } |
| |
| /// EmitBuiltinCall - stmt is a call to fndecl, a builtin function. Try to emit |
| /// the call in a special way, setting Result to the scalar result if necessary. |
| /// If we can't handle the builtin, return false, otherwise return true. |
| bool TreeToLLVM::EmitBuiltinCall(gimple stmt, tree fndecl, |
| const MemRef *DestLoc, Value *&Result) { |
| if (DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_MD) { |
| unsigned FnCode = DECL_FUNCTION_CODE(fndecl); |
| if (TargetBuiltinCache.size() <= FnCode) |
| TargetBuiltinCache.resize(FnCode + 1); |
| |
| // If we haven't converted this intrinsic over yet, do so now. |
| if (TargetBuiltinCache[FnCode] == 0) { |
| const char *TargetPrefix = ""; |
| #ifdef LLVM_TARGET_INTRINSIC_PREFIX |
| TargetPrefix = LLVM_TARGET_INTRINSIC_PREFIX; |
| #endif |
| // If the backend has some special code to lower, go ahead and try to |
| // do that first. |
| if (EmitFrontendExpandedBuiltinCall(stmt, fndecl, DestLoc, Result)) |
| return true; |
| |
| // If this builtin directly corresponds to an LLVM intrinsic, get the |
| // IntrinsicID now. |
| const char *BuiltinName = IDENTIFIER_POINTER(DECL_NAME(fndecl)); |
| Intrinsic::ID IntrinsicID = |
| Intrinsic::getIntrinsicForGCCBuiltin(TargetPrefix, BuiltinName); |
| if (IntrinsicID == Intrinsic::not_intrinsic) { |
| error("unsupported target builtin %<%s%> used", BuiltinName); |
| Type *ResTy = ConvertType(gimple_call_return_type(stmt)); |
| if (ResTy->isSingleValueType()) |
| Result = UndefValue::get(ResTy); |
| return true; |
| } |
| |
| // Finally, map the intrinsic ID back to a name. |
| TargetBuiltinCache[FnCode] = |
| Intrinsic::getDeclaration(TheModule, IntrinsicID); |
| } |
| |
| Result = |
| EmitCallOf(TargetBuiltinCache[FnCode], stmt, DestLoc, AttributeSet()); |
| return true; |
| } |
| |
| enum built_in_function fcode = DECL_FUNCTION_CODE(fndecl); |
| switch (fcode) { |
| default: |
| return false; |
| // Varargs builtins. |
| case BUILT_IN_VA_START: |
| return EmitBuiltinVAStart(stmt); |
| case BUILT_IN_VA_END: |
| return EmitBuiltinVAEnd(stmt); |
| case BUILT_IN_VA_COPY: |
| return EmitBuiltinVACopy(stmt); |
| |
| case BUILT_IN_ADJUST_TRAMPOLINE: |
| return EmitBuiltinAdjustTrampoline(stmt, Result); |
| case BUILT_IN_ALLOCA: |
| return EmitBuiltinAlloca(stmt, Result); |
| #if (GCC_MINOR > 6) |
| case BUILT_IN_ALLOCA_WITH_ALIGN: |
| return EmitBuiltinAllocaWithAlign(stmt, Result); |
| #endif |
| #if (GCC_MINOR > 6) |
| case BUILT_IN_ASSUME_ALIGNED: |
| return EmitBuiltinAssumeAligned(stmt, Result); |
| #endif |
| case BUILT_IN_BZERO: |
| return EmitBuiltinBZero(stmt, Result); |
| case BUILT_IN_CONSTANT_P: |
| return EmitBuiltinConstantP(stmt, Result); |
| case BUILT_IN_EXPECT: |
| return EmitBuiltinExpect(stmt, Result); |
| case BUILT_IN_EXTEND_POINTER: |
| return EmitBuiltinExtendPointer(stmt, Result); |
| case BUILT_IN_EXTRACT_RETURN_ADDR: |
| return EmitBuiltinExtractReturnAddr(stmt, Result); |
| case BUILT_IN_FRAME_ADDRESS: |
| return EmitBuiltinReturnAddr(stmt, Result, true); |
| case BUILT_IN_FROB_RETURN_ADDR: |
| return EmitBuiltinFrobReturnAddr(stmt, Result); |
| case BUILT_IN_INIT_TRAMPOLINE: |
| return EmitBuiltinInitTrampoline(stmt, Result); |
| case BUILT_IN_MEMCPY: |
| return EmitBuiltinMemCopy(stmt, Result, false, false); |
| case BUILT_IN_MEMCPY_CHK: |
| return EmitBuiltinMemCopy(stmt, Result, false, true); |
| case BUILT_IN_MEMMOVE: |
| return EmitBuiltinMemCopy(stmt, Result, true, false); |
| case BUILT_IN_MEMMOVE_CHK: |
| return EmitBuiltinMemCopy(stmt, Result, true, true); |
| case BUILT_IN_MEMSET: |
| return EmitBuiltinMemSet(stmt, Result, false); |
| case BUILT_IN_MEMSET_CHK: |
| return EmitBuiltinMemSet(stmt, Result, true); |
| case BUILT_IN_PREFETCH: |
| return EmitBuiltinPrefetch(stmt); |
| case BUILT_IN_RETURN_ADDRESS: |
| return EmitBuiltinReturnAddr(stmt, Result, false); |
| case BUILT_IN_STACK_RESTORE: |
| return EmitBuiltinStackRestore(stmt); |
| case BUILT_IN_STACK_SAVE: |
| return EmitBuiltinStackSave(stmt, Result); |
| case BUILT_IN_UNREACHABLE: |
| return EmitBuiltinUnreachable(); |
| |
| // Exception handling builtins. |
| case BUILT_IN_EH_COPY_VALUES: |
| return EmitBuiltinEHCopyValues(stmt); |
| case BUILT_IN_EH_FILTER: |
| return EmitBuiltinEHFilter(stmt, Result); |
| case BUILT_IN_EH_POINTER: |
| return EmitBuiltinEHPointer(stmt, Result); |
| |
| // Builtins used by the exception handling runtime. |
| case BUILT_IN_DWARF_CFA: |
| return EmitBuiltinDwarfCFA(stmt, Result); |
| #ifdef DWARF2_UNWIND_INFO |
| case BUILT_IN_DWARF_SP_COLUMN: |
| return EmitBuiltinDwarfSPColumn(stmt, Result); |
| case BUILT_IN_INIT_DWARF_REG_SIZES: |
| return EmitBuiltinInitDwarfRegSizes(stmt, Result); |
| #endif |
| case BUILT_IN_EH_RETURN: |
| return EmitBuiltinEHReturn(stmt, Result); |
| #ifdef EH_RETURN_DATA_REGNO |
| case BUILT_IN_EH_RETURN_DATA_REGNO: |
| return EmitBuiltinEHReturnDataRegno(stmt, Result); |
| #endif |
| case BUILT_IN_UNWIND_INIT: |
| return EmitBuiltinUnwindInit(stmt, Result); |
| |
| case BUILT_IN_OBJECT_SIZE: { |
| if (!validate_gimple_arglist(stmt, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) { |
| error("Invalid builtin_object_size argument types"); |
| return false; |
| } |
| tree ObjSizeTree = gimple_call_arg(stmt, 1); |
| STRIP_NOPS(ObjSizeTree); |
| if (!isa<INTEGER_CST>(ObjSizeTree) || tree_int_cst_sgn(ObjSizeTree) < 0 || |
| compare_tree_int(ObjSizeTree, 3) > 0) { |
| error("Invalid second builtin_object_size argument"); |
| return false; |
| } |
| |
| // LLVM doesn't handle type 1 or type 3. Deal with that here. |
| Value *Tmp = EmitMemory(gimple_call_arg(stmt, 1)); |
| |
| ConstantInt *CI = cast<ConstantInt>(Tmp); |
| |
| // Clear the bottom bit since we only handle whole objects and shift to turn |
| // the second bit into our boolean. |
| uint64_t val = (CI->getZExtValue() & 0x2) >> 1; |
| |
| Value *NewTy = ConstantInt::get(Tmp->getType(), val); |
| |
| Value *Args[] = { EmitMemory(gimple_call_arg(stmt, 0)), NewTy }; |
| |
| // Grab the current return type. |
| Type *Ty = ConvertType(gimple_call_return_type(stmt)); |
| |
| // Manually coerce the arg to the correct pointer type. |
| Args[0] = Builder.CreateBitCast(Args[0], Type::getInt8PtrTy(Context)); |
| Args[1] = Builder.CreateIntCast(Args[1], Type::getInt1Ty(Context), |
| /*isSigned*/ false); |
| |
| Result = Builder.CreateCall( |
| Intrinsic::getDeclaration(TheModule, Intrinsic::objectsize, Ty), Args); |
| return true; |
| } |
| // Unary bit counting intrinsics. |
| // NOTE: do not merge these case statements. That will cause the memoized |
| // Function* to be incorrectly shared across the different typed functions. |
| case BUILT_IN_CLZ: // These GCC builtins always return int. |
| case BUILT_IN_CLZL: |
| case BUILT_IN_CLZLL: |
| Result = EmitBuiltinBitCountIntrinsic(stmt, Intrinsic::ctlz); |
| return true; |
| case BUILT_IN_CTZ: // These GCC builtins always return int. |
| case BUILT_IN_CTZL: |
| case BUILT_IN_CTZLL: |
| Result = EmitBuiltinBitCountIntrinsic(stmt, Intrinsic::cttz); |
| return true; |
| case BUILT_IN_PARITYLL: |
| case BUILT_IN_PARITYL: |
| case BUILT_IN_PARITY: { |
| Value *Amt = EmitMemory(gimple_call_arg(stmt, 0)); |
| EmitBuiltinUnaryOp(Amt, Result, Intrinsic::ctpop); |
| Result = Builder.CreateBinOp(Instruction::And, Result, |
| ConstantInt::get(Result->getType(), 1)); |
| tree return_type = gimple_call_return_type(stmt); |
| Type *DestTy = ConvertType(return_type); |
| Result = Builder.CreateIntCast( |
| Result, DestTy, /*isSigned*/ !TYPE_UNSIGNED(return_type), "cast"); |
| return true; |
| } |
| case BUILT_IN_POPCOUNT: // These GCC builtins always return int. |
| case BUILT_IN_POPCOUNTL: |
| case BUILT_IN_POPCOUNTLL: { |
| Value *Amt = EmitMemory(gimple_call_arg(stmt, 0)); |
| EmitBuiltinUnaryOp(Amt, Result, Intrinsic::ctpop); |
| tree return_type = gimple_call_return_type(stmt); |
| Type *DestTy = ConvertType(return_type); |
| Result = Builder.CreateIntCast( |
| Result, DestTy, /*isSigned*/ !TYPE_UNSIGNED(return_type), "cast"); |
| return true; |
| } |
| case BUILT_IN_BSWAP32: |
| case BUILT_IN_BSWAP64: { |
| Value *Amt = EmitMemory(gimple_call_arg(stmt, 0)); |
| EmitBuiltinUnaryOp(Amt, Result, Intrinsic::bswap); |
| tree return_type = gimple_call_return_type(stmt); |
| Type *DestTy = ConvertType(return_type); |
| Result = Builder.CreateIntCast( |
| Result, DestTy, /*isSigned*/ !TYPE_UNSIGNED(return_type), "cast"); |
| return true; |
| } |
| |
| case BUILT_IN_SQRT: |
| case BUILT_IN_SQRTF: |
| case BUILT_IN_SQRTL: |
| // The result of sqrt(negative) is implementation-defined, but follows |
| // IEEE754 in most current implementations. llvm.sqrt, which has undefined |
| // behavior for such inputs, is an inappropriate substitute. |
| break; |
| case BUILT_IN_POWI: |
| case BUILT_IN_POWIF: |
| case BUILT_IN_POWIL: |
| Result = EmitBuiltinPOWI(stmt); |
| return true; |
| case BUILT_IN_POW: |
| case BUILT_IN_POWF: |
| case BUILT_IN_POWL: |
| // If errno math has been disabled, expand these to llvm.pow calls. |
| if (!flag_errno_math) { |
| Result = EmitBuiltinPOW(stmt); |
| return true; |
| } |
| break; |
| case BUILT_IN_LOG: |
| case BUILT_IN_LOGF: |
| case BUILT_IN_LOGL: |
| // If errno math has been disabled, expand these to llvm.log calls. |
| if (!flag_errno_math) { |
| Value *Amt = EmitMemory(gimple_call_arg(stmt, 0)); |
| EmitBuiltinUnaryOp(Amt, Result, Intrinsic::log); |
| Result = CastToFPType(Result, ConvertType(gimple_call_return_type(stmt))); |
| return true; |
| } |
| break; |
| case BUILT_IN_LOG2: |
| case BUILT_IN_LOG2F: |
| case BUILT_IN_LOG2L: |
| // If errno math has been disabled, expand these to llvm.log2 calls. |
| if (!flag_errno_math) { |
| Value *Amt = EmitMemory(gimple_call_arg(stmt, 0)); |
| EmitBuiltinUnaryOp(Amt, Result, Intrinsic::log2); |
| Result = CastToFPType(Result, ConvertType(gimple_call_return_type(stmt))); |
| return true; |
| } |
| break; |
| case BUILT_IN_LOG10: |
| case BUILT_IN_LOG10F: |
| case BUILT_IN_LOG10L: |
| // If errno math has been disabled, expand these to llvm.log10 calls. |
| if (!flag_errno_math) { |
| Value *Amt = EmitMemory(gimple_call_arg(stmt, 0)); |
| EmitBuiltinUnaryOp(Amt, Result, Intrinsic::log10); |
| Result = CastToFPType(Result, ConvertType(gimple_call_return_type(stmt))); |
| return true; |
| } |
| break; |
| case BUILT_IN_EXP: |
| case BUILT_IN_EXPF: |
| case BUILT_IN_EXPL: |
| // If errno math has been disabled, expand these to llvm.exp calls. |
| if (!flag_errno_math) { |
| Value *Amt = EmitMemory(gimple_call_arg(stmt, 0)); |
| EmitBuiltinUnaryOp(Amt, Result, Intrinsic::exp); |
| Result = CastToFPType(Result, ConvertType(gimple_call_return_type(stmt))); |
| return true; |
| } |
| break; |
| case BUILT_IN_EXP2: |
| case BUILT_IN_EXP2F: |
| case BUILT_IN_EXP2L: |
| // If errno math has been disabled, expand these to llvm.exp2 calls. |
| if (!flag_errno_math) { |
| Value *Amt = EmitMemory(gimple_call_arg(stmt, 0)); |
| EmitBuiltinUnaryOp(Amt, Result, Intrinsic::exp2); |
| Result = CastToFPType(Result, ConvertType(gimple_call_return_type(stmt))); |
| return true; |
| } |
| break; |
| case BUILT_IN_FFS: // These GCC builtins always return int. |
| case BUILT_IN_FFSL: |
| case BUILT_IN_FFSLL: { // FFS(X) -> (x == 0 ? 0 : CTTZ(x)+1) |
| // The argument and return type of cttz should match the argument type of |
| // the ffs, but should ignore the return type of ffs. |
| Value *Amt = EmitMemory(gimple_call_arg(stmt, 0)); |
| Result = Builder.CreateCall2( |
| Intrinsic::getDeclaration(TheModule, Intrinsic::cttz, Amt->getType()), |
| Amt, Builder.getTrue()); |
| Result = Builder.CreateAdd(Result, ConstantInt::get(Result->getType(), 1)); |
| Result = Builder.CreateIntCast( |
| Result, ConvertType(gimple_call_return_type(stmt)), /*isSigned*/ false); |
| Value *Cond = |
| Builder.CreateICmpEQ(Amt, Constant::getNullValue(Amt->getType())); |
| Result = Builder.CreateSelect( |
| Cond, Constant::getNullValue(Result->getType()), Result); |
| return true; |
| } |
| #if (GCC_MINOR > 6) |
| case BUILT_IN_ICEIL: |
| case BUILT_IN_ICEILF: |
| case BUILT_IN_ICEILL: |
| #endif |
| case BUILT_IN_LCEIL: |
| case BUILT_IN_LCEILF: |
| case BUILT_IN_LCEILL: |
| case BUILT_IN_LLCEIL: |
| case BUILT_IN_LLCEILF: |
| case BUILT_IN_LLCEILL: |
| Result = EmitBuiltinLCEIL(stmt); |
| return true; |
| #if (GCC_MINOR > 6) |
| case BUILT_IN_IFLOOR: |
| case BUILT_IN_IFLOORF: |
| case BUILT_IN_IFLOORL: |
| #endif |
| case BUILT_IN_LFLOOR: |
| case BUILT_IN_LFLOORF: |
| case BUILT_IN_LFLOORL: |
| case BUILT_IN_LLFLOOR: |
| case BUILT_IN_LLFLOORF: |
| case BUILT_IN_LLFLOORL: |
| Result = EmitBuiltinLFLOOR(stmt); |
| return true; |
| case BUILT_IN_CEXPI: |
| case BUILT_IN_CEXPIF: |
| case BUILT_IN_CEXPIL: |
| Result = EmitBuiltinCEXPI(stmt); |
| return true; |
| //TODO case BUILT_IN_FLT_ROUNDS: { |
| //TODO Result = |
| //TODO Builder.CreateCall(Intrinsic::getDeclaration(TheModule, |
| //TODO Intrinsic::flt_rounds)); |
| //TODO Result = Builder.CreateBitCast(Result, ConvertType(gimple_call_return_type(stmt))); |
| //TODO return true; |
| //TODO } |
| case BUILT_IN_TRAP: |
| Builder.CreateCall(Intrinsic::getDeclaration(TheModule, Intrinsic::trap)); |
| // Emit an explicit unreachable instruction. |
| Builder.CreateUnreachable(); |
| BeginBlock(BasicBlock::Create(Context)); |
| return true; |
| |
| //TODO // Convert annotation built-in to llvm.annotation intrinsic. |
| //TODO case BUILT_IN_ANNOTATION: { |
| //TODO |
| //TODO // Get file and line number |
| //TODO location_t locus = gimple_location(stmt); |
| //TODO Constant *lineNo = ConstantInt::get(Type::getInt32Ty, LOCATION_LINE(locus)); |
| //TODO Constant *file = ConvertMetadataStringToGV(LOCATION_FILE(locus)); |
| //TODO Type *SBP= Type::getInt8PtrTy(Context); |
| //TODO file = TheFolder->CreateBitCast(file, SBP); |
| //TODO |
| //TODO // Get arguments. |
| //TODO tree arglist = CALL_EXPR_ARGS(stmt); |
| //TODO Value *ExprVal = EmitMemory(gimple_call_arg(stmt, 0)); |
| //TODO Type *Ty = ExprVal->getType(); |
| //TODO Value *StrVal = EmitMemory(gimple_call_arg(stmt, 1)); |
| //TODO |
| //TODO SmallVector<Value *, 4> Args; |
| //TODO Args.push_back(ExprVal); |
| //TODO Args.push_back(StrVal); |
| //TODO Args.push_back(file); |
| //TODO Args.push_back(lineNo); |
| //TODO |
| //TODO assert(Ty && "llvm.annotation arg type may not be null"); |
| //TODO Result = Builder.CreateCall(Intrinsic::getDeclaration(TheModule, |
| //TODO Intrinsic::annotation, |
| //TODO &Ty, |
| //TODO 1), |
| //TODO Args.begin(), Args.end()); |
| //TODO return true; |
| //TODO } |
| |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_SYNCHRONIZE: |
| #else |
| case BUILT_IN_SYNC_SYNCHRONIZE: |
| #endif |
| // We assume like gcc appears to, that this only applies to cached memory. |
| Builder.CreateFence(llvm::SequentiallyConsistent); |
| return true; |
| #if defined(TARGET_ALPHA) || defined(TARGET_386) || defined(TARGET_POWERPC) || \ |
| defined(TARGET_ARM) |
| // gcc uses many names for the sync intrinsics |
| // The type of the first argument is not reliable for choosing the |
| // right llvm function; if the original type is not volatile, gcc has |
| // helpfully changed it to "volatile void *" at this point. The |
| // original type can be recovered from the function type in most cases. |
| // For lock_release and bool_compare_and_swap even that is not good |
| // enough, we have to key off the opcode. |
| // Note that Intrinsic::getDeclaration expects the type list in reversed |
| // order, while CreateCall expects the parameter list in normal order. |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_BOOL_COMPARE_AND_SWAP_1: |
| #else |
| case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_1: |
| #endif |
| Result = BuildCmpAndSwapAtomic(stmt, BITS_PER_UNIT, true); |
| return true; |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_BOOL_COMPARE_AND_SWAP_2: |
| #else |
| case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_2: |
| #endif |
| Result = BuildCmpAndSwapAtomic(stmt, 2 * BITS_PER_UNIT, true); |
| return true; |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_BOOL_COMPARE_AND_SWAP_4: |
| #else |
| case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4: |
| #endif |
| Result = BuildCmpAndSwapAtomic(stmt, 4 * BITS_PER_UNIT, true); |
| return true; |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_BOOL_COMPARE_AND_SWAP_8: |
| #else |
| case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8: |
| #endif |
| #if defined(TARGET_POWERPC) |
| if (!TARGET_64BIT) |
| return false; |
| #endif |
| Result = BuildCmpAndSwapAtomic(stmt, 8 * BITS_PER_UNIT, true); |
| return true; |
| |
| // Fall through. |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_VAL_COMPARE_AND_SWAP_1: |
| #else |
| case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_1: |
| #endif |
| Result = BuildCmpAndSwapAtomic(stmt, BITS_PER_UNIT, false); |
| return true; |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_VAL_COMPARE_AND_SWAP_2: |
| #else |
| case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_2: |
| #endif |
| Result = BuildCmpAndSwapAtomic(stmt, 2 * BITS_PER_UNIT, false); |
| return true; |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_VAL_COMPARE_AND_SWAP_4: |
| #else |
| case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_4: |
| #endif |
| Result = BuildCmpAndSwapAtomic(stmt, 4 * BITS_PER_UNIT, false); |
| return true; |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_VAL_COMPARE_AND_SWAP_8: |
| #else |
| case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_8: |
| #endif |
| #if defined(TARGET_POWERPC) |
| if (!TARGET_64BIT) |
| return false; |
| #endif |
| Result = BuildCmpAndSwapAtomic(stmt, 8 * BITS_PER_UNIT, false); |
| return true; |
| |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_FETCH_AND_ADD_8: |
| #else |
| case BUILT_IN_SYNC_FETCH_AND_ADD_8: |
| #endif |
| #if defined(TARGET_POWERPC) |
| if (!TARGET_64BIT) |
| return false; |
| #endif |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_FETCH_AND_ADD_1: |
| case BUILT_IN_FETCH_AND_ADD_2: |
| case BUILT_IN_FETCH_AND_ADD_4: { |
| #else |
| case BUILT_IN_SYNC_FETCH_AND_ADD_1: |
| case BUILT_IN_SYNC_FETCH_AND_ADD_2: |
| case BUILT_IN_SYNC_FETCH_AND_ADD_4: { |
| #endif |
| Result = BuildBinaryAtomic(stmt, AtomicRMWInst::Add); |
| return true; |
| } |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_FETCH_AND_SUB_8: |
| #else |
| case BUILT_IN_SYNC_FETCH_AND_SUB_8: |
| #endif |
| #if defined(TARGET_POWERPC) |
| if (!TARGET_64BIT) |
| return false; |
| #endif |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_FETCH_AND_SUB_1: |
| case BUILT_IN_FETCH_AND_SUB_2: |
| case BUILT_IN_FETCH_AND_SUB_4: { |
| #else |
| case BUILT_IN_SYNC_FETCH_AND_SUB_1: |
| case BUILT_IN_SYNC_FETCH_AND_SUB_2: |
| case BUILT_IN_SYNC_FETCH_AND_SUB_4: { |
| #endif |
| Result = BuildBinaryAtomic(stmt, AtomicRMWInst::Sub); |
| return true; |
| } |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_FETCH_AND_OR_8: |
| #else |
| case BUILT_IN_SYNC_FETCH_AND_OR_8: |
| #endif |
| #if defined(TARGET_POWERPC) |
| if (!TARGET_64BIT) |
| return false; |
| #endif |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_FETCH_AND_OR_1: |
| case BUILT_IN_FETCH_AND_OR_2: |
| case BUILT_IN_FETCH_AND_OR_4: { |
| #else |
| case BUILT_IN_SYNC_FETCH_AND_OR_1: |
| case BUILT_IN_SYNC_FETCH_AND_OR_2: |
| case BUILT_IN_SYNC_FETCH_AND_OR_4: { |
| #endif |
| Result = BuildBinaryAtomic(stmt, AtomicRMWInst::Or); |
| return true; |
| } |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_FETCH_AND_AND_8: |
| #else |
| case BUILT_IN_SYNC_FETCH_AND_AND_8: |
| #endif |
| #if defined(TARGET_POWERPC) |
| if (!TARGET_64BIT) |
| return false; |
| #endif |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_FETCH_AND_AND_1: |
| case BUILT_IN_FETCH_AND_AND_2: |
| case BUILT_IN_FETCH_AND_AND_4: { |
| #else |
| case BUILT_IN_SYNC_FETCH_AND_AND_1: |
| case BUILT_IN_SYNC_FETCH_AND_AND_2: |
| case BUILT_IN_SYNC_FETCH_AND_AND_4: { |
| #endif |
| Result = BuildBinaryAtomic(stmt, AtomicRMWInst::And); |
| return true; |
| } |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_FETCH_AND_XOR_8: |
| #else |
| case BUILT_IN_SYNC_FETCH_AND_XOR_8: |
| #endif |
| #if defined(TARGET_POWERPC) |
| if (!TARGET_64BIT) |
| return false; |
| #endif |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_FETCH_AND_XOR_1: |
| case BUILT_IN_FETCH_AND_XOR_2: |
| case BUILT_IN_FETCH_AND_XOR_4: { |
| #else |
| case BUILT_IN_SYNC_FETCH_AND_XOR_1: |
| case BUILT_IN_SYNC_FETCH_AND_XOR_2: |
| case BUILT_IN_SYNC_FETCH_AND_XOR_4: { |
| #endif |
| Result = BuildBinaryAtomic(stmt, AtomicRMWInst::Xor); |
| return true; |
| } |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_FETCH_AND_NAND_8: |
| #else |
| case BUILT_IN_SYNC_FETCH_AND_NAND_8: |
| #endif |
| #if defined(TARGET_POWERPC) |
| if (!TARGET_64BIT) |
| return false; |
| #endif |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_FETCH_AND_NAND_1: |
| case BUILT_IN_FETCH_AND_NAND_2: |
| case BUILT_IN_FETCH_AND_NAND_4: { |
| #else |
| case BUILT_IN_SYNC_FETCH_AND_NAND_1: |
| case BUILT_IN_SYNC_FETCH_AND_NAND_2: |
| case BUILT_IN_SYNC_FETCH_AND_NAND_4: { |
| #endif |
| Result = BuildBinaryAtomic(stmt, AtomicRMWInst::Nand); |
| return true; |
| } |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_LOCK_TEST_AND_SET_8: |
| #else |
| case BUILT_IN_SYNC_LOCK_TEST_AND_SET_8: |
| #endif |
| #if defined(TARGET_POWERPC) |
| if (!TARGET_64BIT) |
| return false; |
| #endif |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_LOCK_TEST_AND_SET_1: |
| case BUILT_IN_LOCK_TEST_AND_SET_2: |
| case BUILT_IN_LOCK_TEST_AND_SET_4: { |
| #else |
| case BUILT_IN_SYNC_LOCK_TEST_AND_SET_1: |
| case BUILT_IN_SYNC_LOCK_TEST_AND_SET_2: |
| case BUILT_IN_SYNC_LOCK_TEST_AND_SET_4: { |
| #endif |
| Result = BuildBinaryAtomic(stmt, AtomicRMWInst::Xchg); |
| return true; |
| } |
| |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_ADD_AND_FETCH_8: |
| #else |
| case BUILT_IN_SYNC_ADD_AND_FETCH_8: |
| #endif |
| #if defined(TARGET_POWERPC) |
| if (!TARGET_64BIT) |
| return false; |
| #endif |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_ADD_AND_FETCH_1: |
| case BUILT_IN_ADD_AND_FETCH_2: |
| case BUILT_IN_ADD_AND_FETCH_4: |
| #else |
| case BUILT_IN_SYNC_ADD_AND_FETCH_1: |
| case BUILT_IN_SYNC_ADD_AND_FETCH_2: |
| case BUILT_IN_SYNC_ADD_AND_FETCH_4: |
| #endif |
| Result = BuildBinaryAtomic(stmt, AtomicRMWInst::Add, Instruction::Add); |
| return true; |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_SUB_AND_FETCH_8: |
| #else |
| case BUILT_IN_SYNC_SUB_AND_FETCH_8: |
| #endif |
| #if defined(TARGET_POWERPC) |
| if (!TARGET_64BIT) |
| return false; |
| #endif |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_SUB_AND_FETCH_1: |
| case BUILT_IN_SUB_AND_FETCH_2: |
| case BUILT_IN_SUB_AND_FETCH_4: |
| #else |
| case BUILT_IN_SYNC_SUB_AND_FETCH_1: |
| case BUILT_IN_SYNC_SUB_AND_FETCH_2: |
| case BUILT_IN_SYNC_SUB_AND_FETCH_4: |
| #endif |
| Result = BuildBinaryAtomic(stmt, AtomicRMWInst::Sub, Instruction::Sub); |
| return true; |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_OR_AND_FETCH_8: |
| #else |
| case BUILT_IN_SYNC_OR_AND_FETCH_8: |
| #endif |
| #if defined(TARGET_POWERPC) |
| if (!TARGET_64BIT) |
| return false; |
| #endif |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_OR_AND_FETCH_1: |
| case BUILT_IN_OR_AND_FETCH_2: |
| case BUILT_IN_OR_AND_FETCH_4: |
| #else |
| case BUILT_IN_SYNC_OR_AND_FETCH_1: |
| case BUILT_IN_SYNC_OR_AND_FETCH_2: |
| case BUILT_IN_SYNC_OR_AND_FETCH_4: |
| #endif |
| Result = BuildBinaryAtomic(stmt, AtomicRMWInst::Or, Instruction::Or); |
| return true; |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_AND_AND_FETCH_8: |
| #else |
| case BUILT_IN_SYNC_AND_AND_FETCH_8: |
| #endif |
| #if defined(TARGET_POWERPC) |
| if (!TARGET_64BIT) |
| return false; |
| #endif |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_AND_AND_FETCH_1: |
| case BUILT_IN_AND_AND_FETCH_2: |
| case BUILT_IN_AND_AND_FETCH_4: |
| #else |
| case BUILT_IN_SYNC_AND_AND_FETCH_1: |
| case BUILT_IN_SYNC_AND_AND_FETCH_2: |
| case BUILT_IN_SYNC_AND_AND_FETCH_4: |
| #endif |
| Result = BuildBinaryAtomic(stmt, AtomicRMWInst::And, Instruction::And); |
| return true; |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_XOR_AND_FETCH_8: |
| #else |
| case BUILT_IN_SYNC_XOR_AND_FETCH_8: |
| #endif |
| #if defined(TARGET_POWERPC) |
| if (!TARGET_64BIT) |
| return false; |
| #endif |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_XOR_AND_FETCH_1: |
| case BUILT_IN_XOR_AND_FETCH_2: |
| case BUILT_IN_XOR_AND_FETCH_4: |
| #else |
| case BUILT_IN_SYNC_XOR_AND_FETCH_1: |
| case BUILT_IN_SYNC_XOR_AND_FETCH_2: |
| case BUILT_IN_SYNC_XOR_AND_FETCH_4: |
| #endif |
| Result = BuildBinaryAtomic(stmt, AtomicRMWInst::Xor, Instruction::Xor); |
| return true; |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_NAND_AND_FETCH_8: |
| #else |
| case BUILT_IN_SYNC_NAND_AND_FETCH_8: |
| #endif |
| #if defined(TARGET_POWERPC) |
| if (!TARGET_64BIT) |
| return false; |
| #endif |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_NAND_AND_FETCH_1: |
| case BUILT_IN_NAND_AND_FETCH_2: |
| case BUILT_IN_NAND_AND_FETCH_4: { |
| #else |
| case BUILT_IN_SYNC_NAND_AND_FETCH_1: |
| case BUILT_IN_SYNC_NAND_AND_FETCH_2: |
| case BUILT_IN_SYNC_NAND_AND_FETCH_4: { |
| #endif |
| tree return_type = gimple_call_return_type(stmt); |
| Type *ResultTy = ConvertType(return_type); |
| Value *C[2] = { EmitMemory(gimple_call_arg(stmt, 0)), |
| EmitMemory(gimple_call_arg(stmt, 1)) }; |
| C[0] = Builder.CreateBitCast(C[0], ResultTy->getPointerTo()); |
| C[1] = Builder.CreateIntCast( |
| C[1], ResultTy, /*isSigned*/ !TYPE_UNSIGNED(return_type), "cast"); |
| Result = Builder.CreateAtomicRMW(AtomicRMWInst::Nand, C[0], C[1], |
| SequentiallyConsistent); |
| |
| Result = Builder.CreateAnd(Builder.CreateNot(Result), C[1]); |
| Result = Builder.CreateIntToPtr(Result, ResultTy); |
| return true; |
| } |
| |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_LOCK_RELEASE_1: |
| case BUILT_IN_LOCK_RELEASE_2: |
| case BUILT_IN_LOCK_RELEASE_4: |
| case BUILT_IN_LOCK_RELEASE_8: |
| case BUILT_IN_LOCK_RELEASE_16: { |
| #else |
| case BUILT_IN_SYNC_LOCK_RELEASE_1: |
| case BUILT_IN_SYNC_LOCK_RELEASE_2: |
| case BUILT_IN_SYNC_LOCK_RELEASE_4: |
| case BUILT_IN_SYNC_LOCK_RELEASE_8: |
| case BUILT_IN_SYNC_LOCK_RELEASE_16: { |
| #endif |
| // This is effectively a volatile store of 0, and has no return value. |
| // The argument has typically been coerced to "volatile void*"; the |
| // only way to find the size of the operation is from the builtin |
| // opcode. |
| // FIXME: This is wrong; it works to some extent on x86 if the optimizer |
| // doesn't get too clever, and is horribly broken anywhere else. It needs |
| // to use "store atomic [...] release". |
| Type *Ty; |
| switch (DECL_FUNCTION_CODE(fndecl)) { |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_LOCK_RELEASE_16: // not handled; should use SSE on x86 |
| #else |
| case BUILT_IN_SYNC_LOCK_RELEASE_16: // not handled; should use SSE on x86 |
| #endif |
| default: |
| llvm_unreachable("Not handled; should use SSE on x86!"); |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_LOCK_RELEASE_1: |
| #else |
| case BUILT_IN_SYNC_LOCK_RELEASE_1: |
| #endif |
| Ty = Type::getInt8Ty(Context); |
| break; |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_LOCK_RELEASE_2: |
| #else |
| case BUILT_IN_SYNC_LOCK_RELEASE_2: |
| #endif |
| Ty = Type::getInt16Ty(Context); |
| break; |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_LOCK_RELEASE_4: |
| #else |
| case BUILT_IN_SYNC_LOCK_RELEASE_4: |
| #endif |
| Ty = Type::getInt32Ty(Context); |
| break; |
| #if (GCC_MINOR < 7) |
| case BUILT_IN_LOCK_RELEASE_8: |
| #else |
| case BUILT_IN_SYNC_LOCK_RELEASE_8: |
| #endif |
| Ty = Type::getInt64Ty(Context); |
| break; |
| } |
| Value *Ptr = EmitMemory(gimple_call_arg(stmt, 0)); |
| Ptr = Builder.CreateBitCast(Ptr, Ty->getPointerTo()); |
| Builder.CreateStore(Constant::getNullValue(Ty), Ptr, true); |
| Result = 0; |
| return true; |
| } |
| |
| #endif //FIXME: these break the build for backends that haven't implemented them |
| |
| #if 1 // FIXME: Should handle these GCC extensions eventually. |
| case BUILT_IN_LONGJMP: { |
| if (validate_gimple_arglist(stmt, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) { |
| tree value = gimple_call_arg(stmt, 1); |
| |
| if (!isa<INTEGER_CST>(value) || |
| cast<ConstantInt>(EmitMemory(value))->getValue() != 1) { |
| error("%<__builtin_longjmp%> second argument must be 1"); |
| return false; |
| } |
| } |
| #if defined(TARGET_ARM) && defined(CONFIG_DARWIN_H) |
| Value *Buf = Emit(TREE_VALUE(arglist), 0); |
| Buf = Builder.CreateBitCast(Buf, Type::getInt8Ty(Context)->getPointerTo()); |
| Builder.CreateCall( |
| Intrinsic::getDeclaration(TheModule, Intrinsic::eh_sjlj_longjmp), Buf); |
| Result = 0; |
| return true; |
| #endif |
| // Fall-through |
| } |
| case BUILT_IN_APPLY_ARGS: |
| case BUILT_IN_APPLY: |
| case BUILT_IN_RETURN: |
| case BUILT_IN_SAVEREGS: |
| #if (GCC_MINOR < 6) |
| case BUILT_IN_ARGS_INFO: |
| #endif |
| case BUILT_IN_NEXT_ARG: |
| case BUILT_IN_CLASSIFY_TYPE: |
| case BUILT_IN_AGGREGATE_INCOMING_ADDRESS: |
| case BUILT_IN_SETJMP_SETUP: |
| case BUILT_IN_SETJMP_DISPATCHER: |
| case BUILT_IN_SETJMP_RECEIVER: |
| case BUILT_IN_UPDATE_SETJMP_BUF: |
| // FIXME: HACK: Just ignore these. |
| { |
| Type *Ty = ConvertType(gimple_call_return_type(stmt)); |
| if (!Ty->isVoidTy()) |
| Result = Constant::getNullValue(Ty); |
| return true; |
| } |
| #endif // FIXME: Should handle these GCC extensions eventually. |
| } |
| return false; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinUnaryOp(Value * InVal, Value * &Result, |
| Intrinsic::ID Id) { |
| // The intrinsic might be overloaded in which case the argument is of |
| // varying type. Make sure that we specify the actual type for "iAny" |
| // by passing it as the 3rd and 4th parameters. This isn't needed for |
| // most intrinsics, but is needed for ctpop, cttz, ctlz. |
| Type *Ty = InVal->getType(); |
| Result = Builder.CreateCall(Intrinsic::getDeclaration(TheModule, Id, Ty), |
| InVal); |
| return true; |
| } |
| |
| Value *TreeToLLVM::EmitBuiltinBitCountIntrinsic(gimple stmt, |
| Intrinsic::ID Id) { |
| Value *Amt = EmitMemory(gimple_call_arg(stmt, 0)); |
| Value *Result = Builder.CreateCall2( |
| Intrinsic::getDeclaration(TheModule, Id, Amt->getType()), Amt, |
| Builder.getTrue()); |
| tree return_type = gimple_call_return_type(stmt); |
| Type *DestTy = ConvertType(return_type); |
| return Builder.CreateIntCast( |
| Result, DestTy, /*isSigned*/ !TYPE_UNSIGNED(return_type), "cast"); |
| } |
| |
| Value *TreeToLLVM::EmitBuiltinSQRT(gimple stmt) { |
| Value *Amt = EmitMemory(gimple_call_arg(stmt, 0)); |
| Type *Ty = Amt->getType(); |
| |
| return Builder.CreateCall( |
| Intrinsic::getDeclaration(TheModule, Intrinsic::sqrt, Ty), Amt); |
| } |
| |
| Value *TreeToLLVM::EmitBuiltinPOWI(gimple stmt) { |
| if (!validate_gimple_arglist(stmt, REAL_TYPE, INTEGER_TYPE, VOID_TYPE)) |
| return 0; |
| |
| Value *Val = EmitMemory(gimple_call_arg(stmt, 0)); |
| Value *Pow = EmitMemory(gimple_call_arg(stmt, 1)); |
| Type *Ty = Val->getType(); |
| Pow = Builder.CreateIntCast(Pow, Type::getInt32Ty(Context), |
| /*isSigned*/ true); |
| |
| SmallVector<Value *, 2> Args; |
| Args.push_back(Val); |
| Args.push_back(Pow); |
| return Builder.CreateCall( |
| Intrinsic::getDeclaration(TheModule, Intrinsic::powi, Ty), Args); |
| } |
| |
| Value *TreeToLLVM::EmitBuiltinPOW(gimple stmt) { |
| if (!validate_gimple_arglist(stmt, REAL_TYPE, REAL_TYPE, VOID_TYPE)) |
| return 0; |
| |
| Value *Val = EmitMemory(gimple_call_arg(stmt, 0)); |
| Value *Pow = EmitMemory(gimple_call_arg(stmt, 1)); |
| Type *Ty = Val->getType(); |
| |
| SmallVector<Value *, 2> Args; |
| Args.push_back(Val); |
| Args.push_back(Pow); |
| return Builder.CreateCall( |
| Intrinsic::getDeclaration(TheModule, Intrinsic::pow, Ty), Args); |
| } |
| |
| Value *TreeToLLVM::EmitBuiltinLCEIL(gimple stmt) { |
| if (!validate_gimple_arglist(stmt, REAL_TYPE, VOID_TYPE)) |
| return 0; |
| |
| // Cast the result of "ceil" to the appropriate integer type. |
| // First call the appropriate version of "ceil". |
| tree op = gimple_call_arg(stmt, 0); |
| StringRef Name = SelectFPName(TREE_TYPE(op), "ceilf", "ceil", "ceill"); |
| assert(!Name.empty() && "Unsupported floating point type!"); |
| CallInst *Call = EmitSimpleCall(Name, TREE_TYPE(op), op, NULL); |
| Call->setDoesNotThrow(); |
| Call->setDoesNotAccessMemory(); |
| |
| // Then type cast the result of the "ceil" call. |
| tree type = gimple_call_return_type(stmt); |
| Type *RetTy = getRegType(type); |
| return TYPE_UNSIGNED(type) ? Builder.CreateFPToUI(Call, RetTy) |
| : Builder.CreateFPToSI(Call, RetTy); |
| } |
| |
| Value *TreeToLLVM::EmitBuiltinLFLOOR(gimple stmt) { |
| if (!validate_gimple_arglist(stmt, REAL_TYPE, VOID_TYPE)) |
| return 0; |
| |
| // Cast the result of "floor" to the appropriate integer type. |
| // First call the appropriate version of "floor". |
| tree op = gimple_call_arg(stmt, 0); |
| StringRef Name = SelectFPName(TREE_TYPE(op), "floorf", "floor", "floorl"); |
| assert(!Name.empty() && "Unsupported floating point type!"); |
| CallInst *Call = EmitSimpleCall(Name, TREE_TYPE(op), op, NULL); |
| Call->setDoesNotThrow(); |
| Call->setDoesNotAccessMemory(); |
| |
| // Then type cast the result of the "floor" call. |
| tree type = gimple_call_return_type(stmt); |
| Type *RetTy = getRegType(type); |
| return TYPE_UNSIGNED(type) ? Builder.CreateFPToUI(Call, RetTy) |
| : Builder.CreateFPToSI(Call, RetTy); |
| } |
| |
| Value *TreeToLLVM::EmitBuiltinCEXPI(gimple stmt) { |
| if (!validate_gimple_arglist(stmt, REAL_TYPE, VOID_TYPE)) |
| return 0; |
| |
| if (TARGET_HAS_SINCOS) { |
| // exp(i*arg) = cos(arg) + i*sin(arg). Emit a call to sincos. First |
| // determine which version of sincos to call. |
| tree arg = gimple_call_arg(stmt, 0); |
| tree arg_type = TREE_TYPE(arg); |
| StringRef Name = SelectFPName(arg_type, "sincosf", "sincos", "sincosl"); |
| assert(!Name.empty() && "Unsupported floating point type!"); |
| |
| // Create stack slots to store the real (cos) and imaginary (sin) parts in. |
| Value *Val = EmitRegister(arg); |
| Value *SinPtr = CreateTemporary(Val->getType()); |
| Value *CosPtr = CreateTemporary(Val->getType()); |
| |
| // Get the LLVM function declaration for sincos. |
| Type *ArgTys[3] = { Val->getType(), SinPtr->getType(), |
| CosPtr->getType() }; |
| FunctionType *FTy = FunctionType::get(Type::getVoidTy(Context), ArgTys, |
| /*isVarArg*/ false); |
| Constant *Func = TheModule->getOrInsertFunction(Name, FTy); |
| |
| // Determine the calling convention. |
| CallingConv::ID CC = CallingConv::C; |
| #ifdef TARGET_ADJUST_LLVM_CC |
| // Query the target for the calling convention to use. |
| tree fntype = build_function_type_list( |
| void_type_node, arg_type, TYPE_POINTER_TO(arg_type), |
| TYPE_POINTER_TO(arg_type), NULL_TREE); |
| TARGET_ADJUST_LLVM_CC(CC, fntype); |
| #endif |
| |
| // If the function already existed with the wrong prototype then don't try to |
| // muck with its calling convention. Otherwise, set the calling convention. |
| if (Function *F = llvm::dyn_cast<Function>(Func)) |
| F->setCallingConv(CC); |
| |
| // Call sincos. |
| Value *Args[3] = { Val, SinPtr, CosPtr }; |
| CallInst *CI = Builder.CreateCall(Func, Args); |
| CI->setCallingConv(CC); |
| CI->setDoesNotThrow(); |
| |
| // Load out the real (cos) and imaginary (sin) parts. |
| Value *Sin = Builder.CreateLoad(SinPtr); |
| Value *Cos = Builder.CreateLoad(CosPtr); |
| |
| // Return the complex number "cos(arg) + i*sin(arg)". |
| return CreateComplex(Cos, Sin); |
| } else { |
| // Emit a call to cexp. First determine which version of cexp to call. |
| tree arg = gimple_call_arg(stmt, 0); |
| tree arg_type = TREE_TYPE(arg); |
| StringRef Name = SelectFPName(arg_type, "cexpf", "cexp", "cexpl"); |
| assert(!Name.empty() && "Unsupported floating point type!"); |
| |
| // Get the GCC and LLVM function types for cexp. |
| tree cplx_type = gimple_call_return_type(stmt); |
| tree fntype = build_function_type_list(cplx_type, cplx_type, NULL_TREE); |
| FunctionType *FTy = cast<FunctionType>(ConvertType(fntype)); |
| |
| // Get the LLVM function declaration for cexp. |
| Constant *Func = TheModule->getOrInsertFunction(Name, FTy); |
| |
| // Determine the calling convention. |
| CallingConv::ID CC = CallingConv::C; |
| #ifdef TARGET_ADJUST_LLVM_CC |
| // Query the target for the calling convention to use. |
| TARGET_ADJUST_LLVM_CC(CC, fntype); |
| #endif |
| |
| // If the function already existed with the wrong prototype then don't try to |
| // muck with its calling convention. Otherwise, set the calling convention. |
| if (Function *F = llvm::dyn_cast<Function>(Func)) |
| F->setCallingConv(CC); |
| |
| // Form the complex number "0 + i*arg". |
| Value *Arg = EmitRegister(arg); |
| Value *CplxArg = |
| CreateComplex(Constant::getNullValue(Arg->getType()), Arg); |
| |
| // Call cexp and return the result. This is rather painful because complex |
| // numbers may be passed in funky ways and we don't have a proper interface |
| // for marshalling call parameters. |
| SmallVector<Value *, 16> CallOperands; |
| FunctionCallArgumentConversion Client(CallOperands, FTy, /*destloc*/ 0, |
| /*ReturnSlotOpt*/ false, Builder, |
| CC); |
| DefaultABI ABIConverter(Client); |
| |
| // Handle the result. |
| ABIConverter.HandleReturnType(cplx_type, fntype, false); |
| |
| // Push the argument. |
| bool PassedInMemory; |
| Type *CplxTy = CplxArg->getType(); |
| if (LLVM_SHOULD_PASS_AGGREGATE_AS_FCA(cplx_type, CplxTy)) { |
| Client.pushValue(CplxArg); |
| PassedInMemory = false; |
| } else { |
| // Push the address of a temporary copy. |
| MemRef Copy = CreateTempLoc(CplxTy); |
| StoreRegisterToMemory(CplxArg, Copy, cplx_type, 0, Builder); |
| Client.pushAddress(Copy.Ptr); |
| PassedInMemory = true; |
| } |
| |
| AttrBuilder AttrBuilder; |
| std::vector<Type *> ScalarArgs; |
| ABIConverter.HandleArgument(cplx_type, ScalarArgs, &AttrBuilder); |
| assert(!AttrBuilder.hasAttributes() && |
| "Got attributes but none given!"); |
| Client.clear(); |
| |
| // Create the call. |
| CallInst *CI = Builder.CreateCall(Func, CallOperands); |
| CI->setCallingConv(CC); |
| CI->setDoesNotThrow(); |
| if (!PassedInMemory) |
| CI->setDoesNotAccessMemory(); |
| |
| // Extract and return the result. |
| if (Client.isShadowReturn()) |
| return Client.EmitShadowResult(cplx_type, 0); |
| |
| if (Client.isAggrReturn()) { |
| // Extract to a temporary then load the value out later. |
| MemRef Target = CreateTempLoc(CplxTy); |
| |
| assert(DL.getTypeAllocSize(CI->getType()) <= |
| DL.getTypeAllocSize(CplxTy) && |
| "Complex number returned in too large registers!"); |
| Value *Dest = |
| Builder.CreateBitCast(Target.Ptr, CI->getType()->getPointerTo()); |
| LLVM_EXTRACT_MULTIPLE_RETURN_VALUE(CI, Dest, Target.Volatile, |
| Builder); |
| return Builder.CreateLoad(Target.Ptr); |
| } |
| |
| if (CI->getType() == CplxTy) |
| return CI; // Normal scalar return. |
| |
| // Probably { float, float } being returned as a double. |
| assert(DL.getTypeAllocSize(CI->getType()) == |
| DL.getTypeAllocSize(CplxTy) && |
| "Size mismatch in scalar to scalar conversion!"); |
| Value *Tmp = CreateTemporary(CI->getType()); |
| Builder.CreateStore(CI, Tmp); |
| Type *CplxPtrTy = CplxTy->getPointerTo(); |
| return Builder.CreateLoad(Builder.CreateBitCast(Tmp, CplxPtrTy)); |
| } |
| } |
| |
| bool TreeToLLVM::EmitBuiltinConstantP(gimple stmt, Value * &Result) { |
| Result = |
| Constant::getNullValue(ConvertType(gimple_call_return_type(stmt))); |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinExtendPointer(gimple stmt, Value * &Result) { |
| tree arg0 = gimple_call_arg(stmt, 0); |
| Value *Amt = EmitMemory(arg0); |
| bool AmtIsSigned = !TYPE_UNSIGNED(TREE_TYPE(arg0)); |
| bool ExpIsSigned = !TYPE_UNSIGNED(gimple_call_return_type(stmt)); |
| Result = CastToAnyType(Amt, AmtIsSigned, |
| ConvertType(gimple_call_return_type(stmt)), |
| ExpIsSigned); |
| return true; |
| } |
| |
| /// OptimizeIntoPlainBuiltIn - Return true if it's safe to lower the object |
| /// size checking builtin calls (e.g. __builtin___memcpy_chk into the |
| /// plain non-checking calls. If the size of the argument is either -1 (unknown) |
| /// or large enough to ensure no overflow (> len), then it's safe to do so. |
| static bool OptimizeIntoPlainBuiltIn(gimple stmt, Value * Len, |
| Value * Size) { |
| if (BitCastInst *SizeBC = llvm::dyn_cast<BitCastInst>(Size)) |
| Size = SizeBC->getOperand(0); |
| ConstantInt *SizeCI = llvm::dyn_cast<ConstantInt>(Size); |
| if (!SizeCI) |
| return false; |
| if (SizeCI->isAllOnesValue()) |
| // If size is -1, convert to plain memcpy, etc. |
| return true; |
| |
| if (BitCastInst *LenBC = llvm::dyn_cast<BitCastInst>(Len)) |
| Len = LenBC->getOperand(0); |
| ConstantInt *LenCI = llvm::dyn_cast<ConstantInt>(Len); |
| if (!LenCI) |
| return false; |
| if (SizeCI->getValue().ult(LenCI->getValue())) { |
| warning(0, "call to %D will always overflow destination buffer", |
| gimple_call_fndecl(stmt)); |
| return false; |
| } |
| return true; |
| } |
| |
| /// EmitBuiltinMemCopy - Emit an llvm.memcpy or llvm.memmove intrinsic, |
| /// depending on the value of isMemMove. |
| bool TreeToLLVM::EmitBuiltinMemCopy(gimple stmt, Value * &Result, |
| bool isMemMove, bool SizeCheck) { |
| if (SizeCheck) { |
| if (!validate_gimple_arglist(stmt, POINTER_TYPE, POINTER_TYPE, |
| INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE)) |
| return false; |
| } else { |
| if (!validate_gimple_arglist(stmt, POINTER_TYPE, POINTER_TYPE, |
| INTEGER_TYPE, VOID_TYPE)) |
| return false; |
| } |
| |
| tree Dst = gimple_call_arg(stmt, 0); |
| tree Src = gimple_call_arg(stmt, 1); |
| unsigned SrcAlign = getPointerAlignment(Src); |
| unsigned DstAlign = getPointerAlignment(Dst); |
| |
| Value *DstV = EmitMemory(Dst); |
| Value *SrcV = EmitMemory(Src); |
| Value *Len = EmitMemory(gimple_call_arg(stmt, 2)); |
| if (SizeCheck) { |
| tree SizeArg = gimple_call_arg(stmt, 3); |
| Value *Size = EmitMemory(SizeArg); |
| if (!OptimizeIntoPlainBuiltIn(stmt, Len, Size)) |
| return false; |
| } |
| |
| Result = |
| isMemMove ? EmitMemMove(DstV, SrcV, Len, std::min(SrcAlign, DstAlign)) |
| : EmitMemCpy(DstV, SrcV, Len, std::min(SrcAlign, DstAlign)); |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinMemSet(gimple stmt, Value * &Result, |
| bool SizeCheck) { |
| if (SizeCheck) { |
| if (!validate_gimple_arglist(stmt, POINTER_TYPE, INTEGER_TYPE, |
| INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE)) |
| return false; |
| } else { |
| if (!validate_gimple_arglist(stmt, POINTER_TYPE, INTEGER_TYPE, |
| INTEGER_TYPE, VOID_TYPE)) |
| return false; |
| } |
| |
| tree Dst = gimple_call_arg(stmt, 0); |
| unsigned DstAlign = getPointerAlignment(Dst); |
| |
| Value *DstV = EmitMemory(Dst); |
| Value *Val = EmitMemory(gimple_call_arg(stmt, 1)); |
| Value *Len = EmitMemory(gimple_call_arg(stmt, 2)); |
| if (SizeCheck) { |
| tree SizeArg = gimple_call_arg(stmt, 3); |
| Value *Size = EmitMemory(SizeArg); |
| if (!OptimizeIntoPlainBuiltIn(stmt, Len, Size)) |
| return false; |
| } |
| Result = EmitMemSet(DstV, Val, Len, DstAlign); |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinBZero(gimple stmt, Value * &/*Result*/) { |
| if (!validate_gimple_arglist(stmt, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) |
| return false; |
| |
| tree Dst = gimple_call_arg(stmt, 0); |
| unsigned DstAlign = getPointerAlignment(Dst); |
| |
| Value *DstV = EmitMemory(Dst); |
| Value *Val = Constant::getNullValue(Type::getInt32Ty(Context)); |
| Value *Len = EmitMemory(gimple_call_arg(stmt, 1)); |
| EmitMemSet(DstV, Val, Len, DstAlign); |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinPrefetch(gimple stmt) { |
| if (!validate_gimple_arglist(stmt, POINTER_TYPE, 0)) |
| return false; |
| |
| Value *Ptr = EmitMemory(gimple_call_arg(stmt, 0)); |
| Value *ReadWrite = 0; |
| Value *Locality = 0; |
| Value *Data = 0; |
| |
| if (gimple_call_num_args(stmt) > 1) { // Args 1/2 are optional |
| ReadWrite = EmitMemory(gimple_call_arg(stmt, 1)); |
| if (!isa<ConstantInt>(ReadWrite)) { |
| error("second argument to %<__builtin_prefetch%> must be a constant"); |
| ReadWrite = 0; |
| } else if (cast<ConstantInt>(ReadWrite)->getZExtValue() > 1) { |
| warning(0, "invalid second argument to %<__builtin_prefetch%>;" |
| " using zero"); |
| ReadWrite = 0; |
| } else { |
| ReadWrite = TheFolder->CreateIntCast(cast<Constant>(ReadWrite), |
| Type::getInt32Ty(Context), |
| /*isSigned*/ false); |
| } |
| |
| if (gimple_call_num_args(stmt) > 2) { |
| Locality = EmitMemory(gimple_call_arg(stmt, 2)); |
| if (!isa<ConstantInt>(Locality)) { |
| error( |
| "third argument to %<__builtin_prefetch%> must be a constant"); |
| Locality = 0; |
| } else if (cast<ConstantInt>(Locality)->getZExtValue() > 3) { |
| warning( |
| 0, "invalid third argument to %<__builtin_prefetch%>; using 3"); |
| Locality = 0; |
| } else { |
| Locality = TheFolder->CreateIntCast(cast<Constant>(Locality), |
| Type::getInt32Ty(Context), |
| /*isSigned*/ false); |
| } |
| } |
| } |
| |
| // Default to highly local read. |
| if (ReadWrite == 0) |
| ReadWrite = Builder.getInt32(0); |
| if (Locality == 0) |
| Locality = Builder.getInt32(3); |
| if (Data == 0) |
| Data = Builder.getInt32(1); |
| |
| Ptr = Builder.CreateBitCast(Ptr, Type::getInt8PtrTy(Context)); |
| |
| Builder.CreateCall4( |
| Intrinsic::getDeclaration(TheModule, Intrinsic::prefetch), Ptr, |
| ReadWrite, Locality, Data); |
| return true; |
| } |
| |
| /// EmitBuiltinReturnAddr - Emit an llvm.returnaddress or llvm.frameaddress |
| /// instruction, depending on whether isFrame is true or not. |
| bool TreeToLLVM::EmitBuiltinReturnAddr(gimple stmt, Value * &Result, |
| bool isFrame) { |
| if (!validate_gimple_arglist(stmt, INTEGER_TYPE, VOID_TYPE)) |
| return false; |
| |
| ConstantInt *Level = |
| llvm::dyn_cast<ConstantInt>(EmitMemory(gimple_call_arg(stmt, 0))); |
| if (!Level) { |
| if (isFrame) |
| error("invalid argument to %<__builtin_frame_address%>"); |
| else |
| error("invalid argument to %<__builtin_return_address%>"); |
| return false; |
| } |
| |
| Intrinsic::ID IID = |
| !isFrame ? Intrinsic::returnaddress : Intrinsic::frameaddress; |
| Result = |
| Builder.CreateCall(Intrinsic::getDeclaration(TheModule, IID), Level); |
| Result = Builder.CreateBitCast( |
| Result, ConvertType(gimple_call_return_type(stmt))); |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinExtractReturnAddr(gimple stmt, |
| Value * &Result) { |
| Value *Ptr = EmitMemory(gimple_call_arg(stmt, 0)); |
| |
| // FIXME: Actually we should do something like this: |
| // |
| // Result = (Ptr & MASK_RETURN_ADDR) + RETURN_ADDR_OFFSET, if mask and |
| // offset are defined. This seems to be needed for: ARM, MIPS, Sparc. |
| // Unfortunately, these constants are defined as RTL expressions and |
| // should be handled separately. |
| |
| Result = Builder.CreateBitCast(Ptr, Type::getInt8PtrTy(Context)); |
| |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinFrobReturnAddr(gimple stmt, Value * &Result) { |
| Value *Ptr = EmitMemory(gimple_call_arg(stmt, 0)); |
| |
| // FIXME: Actually we should do something like this: |
| // |
| // Result = Ptr - RETURN_ADDR_OFFSET, if offset is defined. This seems to be |
| // needed for: MIPS, Sparc. Unfortunately, these constants are defined |
| // as RTL expressions and should be handled separately. |
| |
| Result = Builder.CreateBitCast(Ptr, Type::getInt8PtrTy(Context)); |
| |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinStackSave(gimple stmt, Value * &Result) { |
| if (!validate_gimple_arglist(stmt, VOID_TYPE)) |
| return false; |
| |
| Result = Builder.CreateCall( |
| Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave)); |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinUnreachable() { |
| Builder.CreateUnreachable(); |
| return true; |
| } |
| |
| // Exception handling builtins. |
| |
| bool TreeToLLVM::EmitBuiltinEHCopyValues(gimple stmt) { |
| unsigned DstRegionNo = tree_low_cst(gimple_call_arg(stmt, 0), 0); |
| unsigned SrcRegionNo = tree_low_cst(gimple_call_arg(stmt, 1), 0); |
| // Copy the exception pointer. |
| Value *ExcPtr = Builder.CreateLoad(getExceptionPtr(SrcRegionNo)); |
| Builder.CreateStore(ExcPtr, getExceptionPtr(DstRegionNo)); |
| // Copy the selector value. |
| Value *Filter = Builder.CreateLoad(getExceptionFilter(SrcRegionNo)); |
| Builder.CreateStore(Filter, getExceptionFilter(DstRegionNo)); |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinEHFilter(gimple stmt, Value * &Result) { |
| // Lookup the local that holds the selector value for this region. |
| unsigned RegionNo = tree_low_cst(gimple_call_arg(stmt, 0), 0); |
| AllocaInst *Filter = getExceptionFilter(RegionNo); |
| // Load the selector value out. |
| Result = Builder.CreateLoad(Filter); |
| // Ensure the returned value has the right integer type. |
| tree type = gimple_call_return_type(stmt); |
| Result = CastToAnyType(Result, /*isSigned*/ true, getRegType(type), |
| /*isSigned*/ !TYPE_UNSIGNED(type)); |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinEHPointer(gimple stmt, Value * &Result) { |
| // Lookup the local that holds the exception pointer for this region. |
| unsigned RegionNo = tree_low_cst(gimple_call_arg(stmt, 0), 0); |
| AllocaInst *ExcPtr = getExceptionPtr(RegionNo); |
| // Load the exception pointer out. |
| Result = Builder.CreateLoad(ExcPtr); |
| // Ensure the returned value has the right pointer type. |
| tree type = gimple_call_return_type(stmt); |
| Result = Builder.CreateBitCast(Result, getRegType(type)); |
| return true; |
| } |
| |
| // Builtins used by the exception handling runtime. |
| |
| // On most machines, the CFA coincides with the first incoming parm. |
| #ifndef ARG_POINTER_CFA_OFFSET |
| #define ARG_POINTER_CFA_OFFSET(FNDECL) FIRST_PARM_OFFSET(FNDECL) |
| #endif |
| |
| // The mapping from gcc register number to DWARF 2 CFA column number. By |
| // default, we just provide columns for all registers. |
| #ifndef DWARF_FRAME_REGNUM |
| #define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER(REG) |
| #endif |
| |
| // Map register numbers held in the call frame info that gcc has |
| // collected using DWARF_FRAME_REGNUM to those that should be output in |
| // .debug_frame and .eh_frame. |
| #ifndef DWARF2_FRAME_REG_OUT |
| #define DWARF2_FRAME_REG_OUT(REGNO, FOR_EH) (REGNO) |
| #endif |
| |
| /* Registers that get partially clobbered by a call in a given mode. |
| These must not be call used registers. */ |
| #ifndef HARD_REGNO_CALL_PART_CLOBBERED |
| #define HARD_REGNO_CALL_PART_CLOBBERED(REGNO, MODE) 0 |
| #endif |
| |
| bool TreeToLLVM::EmitBuiltinDwarfCFA(gimple stmt, Value * &Result) { |
| if (!validate_gimple_arglist(stmt, VOID_TYPE)) |
| return false; |
| |
| int cfa_offset = ARG_POINTER_CFA_OFFSET(exp); |
| |
| // FIXME: is i32 always enough here? |
| Result = Builder.CreateCall( |
| Intrinsic::getDeclaration(TheModule, Intrinsic::eh_dwarf_cfa), |
| Builder.getInt32(cfa_offset)); |
| |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinDwarfSPColumn(gimple stmt, Value * &Result) { |
| if (!validate_gimple_arglist(stmt, VOID_TYPE)) |
| return false; |
| |
| unsigned int dwarf_regnum = DWARF_FRAME_REGNUM(STACK_POINTER_REGNUM); |
| Result = ConstantInt::get(ConvertType(gimple_call_return_type(stmt)), |
| dwarf_regnum); |
| |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinEHReturnDataRegno(gimple stmt, |
| Value * &Result) { |
| #ifdef EH_RETURN_DATA_REGNO |
| if (!validate_gimple_arglist(stmt, INTEGER_TYPE, VOID_TYPE)) |
| return false; |
| |
| tree which = gimple_call_arg(stmt, 0); |
| unsigned HOST_WIDE_INT iwhich; |
| |
| if (!isa<INTEGER_CST>(which)) { |
| error("argument of %<__builtin_eh_return_regno%> must be constant"); |
| return false; |
| } |
| |
| iwhich = tree_low_cst(which, 1); |
| iwhich = EH_RETURN_DATA_REGNO(iwhich); |
| if (iwhich == INVALID_REGNUM) |
| return false; |
| |
| iwhich = DWARF_FRAME_REGNUM(iwhich); |
| |
| Result = |
| ConstantInt::get(ConvertType(gimple_call_return_type(stmt)), iwhich); |
| #endif |
| |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinEHReturn(gimple stmt, Value * &/*Result*/) { |
| if (!validate_gimple_arglist(stmt, INTEGER_TYPE, POINTER_TYPE, VOID_TYPE)) |
| return false; |
| |
| Type *IntPtr = DL.getIntPtrType(Context, 0); |
| Value *Offset = EmitMemory(gimple_call_arg(stmt, 0)); |
| Value *Handler = EmitMemory(gimple_call_arg(stmt, 1)); |
| |
| Intrinsic::ID IID = IntPtr->isIntegerTy(32) ? Intrinsic::eh_return_i32 |
| : Intrinsic::eh_return_i64; |
| |
| Offset = Builder.CreateIntCast(Offset, IntPtr, /*isSigned*/ true); |
| Handler = Builder.CreateBitCast(Handler, Type::getInt8PtrTy(Context)); |
| |
| Value *Args[2] = { Offset, Handler }; |
| Builder.CreateCall(Intrinsic::getDeclaration(TheModule, IID), Args); |
| Builder.CreateUnreachable(); |
| BeginBlock(BasicBlock::Create(Context)); |
| |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinInitDwarfRegSizes(gimple stmt, |
| Value * &/*Result*/) { |
| #ifdef DWARF2_UNWIND_INFO |
| unsigned int i; |
| bool wrote_return_column = false; |
| static bool reg_modes_initialized = false; |
| |
| if (!validate_gimple_arglist(stmt, POINTER_TYPE, VOID_TYPE)) |
| return false; |
| |
| if (!reg_modes_initialized) { |
| init_reg_modes_target(); |
| reg_modes_initialized = true; |
| } |
| |
| Value *Addr = Builder.CreateBitCast(EmitMemory(gimple_call_arg(stmt, 0)), |
| Type::getInt8PtrTy(Context)); |
| Constant *Size, *Idx; |
| |
| for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { |
| int rnum = DWARF2_FRAME_REG_OUT(DWARF_FRAME_REGNUM(i), 1); |
| |
| if (rnum < DWARF_FRAME_REGISTERS) { |
| enum machine_mode save_mode = reg_raw_mode[i]; |
| HOST_WIDE_INT size; |
| |
| if (HARD_REGNO_CALL_PART_CLOBBERED(i, save_mode)) |
| save_mode = choose_hard_reg_mode(i, 1, true); |
| if (DWARF_FRAME_REGNUM(i) == DWARF_FRAME_RETURN_COLUMN) { |
| if (save_mode == VOIDmode) |
| continue; |
| wrote_return_column = true; |
| } |
| size = GET_MODE_SIZE(save_mode); |
| if (rnum < 0) |
| continue; |
| |
| Size = Builder.getInt8(size); |
| Idx = Builder.getInt32(rnum); |
| Builder.CreateStore( |
| Size, |
| Builder.CreateGEP(Addr, Idx, flag_verbose_asm ? "rnum" : ""), |
| false); |
| } |
| } |
| |
| if (!wrote_return_column) { |
| Size = Builder.getInt8(GET_MODE_SIZE(Pmode)); |
| Idx = Builder.getInt32(DWARF_FRAME_RETURN_COLUMN); |
| Builder.CreateStore( |
| Size, Builder.CreateGEP(Addr, Idx, flag_verbose_asm ? "rcol" : ""), |
| false); |
| } |
| |
| #ifdef DWARF_ALT_FRAME_RETURN_COLUMN |
| Size = Builder.getInt8(GET_MODE_SIZE(Pmode)); |
| Idx = Builder.getInt32(DWARF_ALT_FRAME_RETURN_COLUMN); |
| Builder.CreateStore( |
| Size, Builder.CreateGEP(Addr, Idx, flag_verbose_asm ? "acol" : ""), |
| false); |
| #endif |
| |
| #endif /* DWARF2_UNWIND_INFO */ |
| |
| // TODO: the RS6000 target needs extra initialization [gcc changeset 122468]. |
| |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinUnwindInit(gimple stmt, Value * &/*Result*/) { |
| if (!validate_gimple_arglist(stmt, VOID_TYPE)) |
| return false; |
| |
| Builder.CreateCall( |
| Intrinsic::getDeclaration(TheModule, Intrinsic::eh_unwind_init)); |
| |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinStackRestore(gimple stmt) { |
| if (!validate_gimple_arglist(stmt, POINTER_TYPE, VOID_TYPE)) |
| return false; |
| |
| Value *Ptr = EmitMemory(gimple_call_arg(stmt, 0)); |
| Ptr = Builder.CreateBitCast(Ptr, Type::getInt8PtrTy(Context)); |
| |
| Builder.CreateCall( |
| Intrinsic::getDeclaration(TheModule, Intrinsic::stackrestore), Ptr); |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinAlloca(gimple stmt, Value * &Result) { |
| if (!validate_gimple_arglist(stmt, INTEGER_TYPE, VOID_TYPE)) |
| return false; |
| Value *Amt = EmitMemory(gimple_call_arg(stmt, 0)); |
| AllocaInst *Alloca = Builder.CreateAlloca(Type::getInt8Ty(Context), Amt); |
| Alloca->setAlignment(BIGGEST_ALIGNMENT / 8); |
| Result = Alloca; |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinAllocaWithAlign(gimple stmt, Value * &Result) { |
| if (!validate_gimple_arglist(stmt, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE)) |
| return false; |
| Value *Amt = EmitMemory(gimple_call_arg(stmt, 0)); |
| uint64_t Align = getInt64(gimple_call_arg(stmt, 1), true); |
| AllocaInst *Alloca = Builder.CreateAlloca(Type::getInt8Ty(Context), Amt); |
| Alloca->setAlignment(Align / 8); |
| Result = Alloca; |
| return true; |
| } |
| |
| #if (GCC_MINOR > 6) |
| bool TreeToLLVM::EmitBuiltinAssumeAligned(gimple stmt, Value * &Result) { |
| if (!validate_gimple_arglist(stmt, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) |
| return false; |
| // Return the pointer argument. TODO: Pass the alignment information on to |
| // the optimizers. |
| Value *Ptr = EmitRegister(gimple_call_arg(stmt, 0)); |
| // Bitcast it to the return type. |
| Ptr = |
| TriviallyTypeConvert(Ptr, getRegType(gimple_call_return_type(stmt))); |
| Result = Reg2Mem(Ptr, gimple_call_return_type(stmt), Builder); |
| return true; |
| } |
| #endif |
| |
| bool TreeToLLVM::EmitBuiltinExpect(gimple stmt, Value * &Result) { |
| tree type = gimple_call_return_type(stmt); |
| if (gimple_call_num_args(stmt) < 2) { |
| Result = Constant::getNullValue(ConvertType(type)); |
| return true; |
| } |
| Type *ArgTy = getRegType(type); |
| Value *ExpectIntr = |
| Intrinsic::getDeclaration(TheModule, Intrinsic::expect, ArgTy); |
| Value *ArgValue = EmitRegister(gimple_call_arg(stmt, 0)); |
| Value *ExpectedValue = EmitRegister(gimple_call_arg(stmt, 1)); |
| Result = Builder.CreateCall2(ExpectIntr, ArgValue, ExpectedValue); |
| Result = Reg2Mem(Result, type, Builder); |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinVAStart(gimple stmt) { |
| if (gimple_call_num_args(stmt) < 2) { |
| error("too few arguments to function %<va_start%>"); |
| return true; |
| } |
| |
| tree fntype = TREE_TYPE(current_function_decl); |
| if (TYPE_ARG_TYPES(fntype) == 0 || |
| (tree_last(TYPE_ARG_TYPES(fntype)) == void_type_node)) { |
| error("%<va_start%> used in function with fixed args"); |
| return true; |
| } |
| |
| Constant *va_start = |
| Intrinsic::getDeclaration(TheModule, Intrinsic::vastart); |
| Value *ArgVal = EmitMemory(gimple_call_arg(stmt, 0)); |
| ArgVal = Builder.CreateBitCast(ArgVal, Type::getInt8PtrTy(Context)); |
| Builder.CreateCall(va_start, ArgVal); |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinVAEnd(gimple stmt) { |
| Value *Arg = EmitMemory(gimple_call_arg(stmt, 0)); |
| Arg = Builder.CreateBitCast(Arg, Type::getInt8PtrTy(Context)); |
| Builder.CreateCall(Intrinsic::getDeclaration(TheModule, Intrinsic::vaend), |
| Arg); |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinVACopy(gimple stmt) { |
| tree Arg1T = gimple_call_arg(stmt, 0); |
| tree Arg2T = gimple_call_arg(stmt, 1); |
| |
| Value *Arg1 = EmitMemory(Arg1T); // Emit the address of the destination. |
| // The second arg of llvm.va_copy is a pointer to a valist. |
| Value *Arg2; |
| if (!isa<AGGREGATE_TYPE>(va_list_type_node)) { |
| // Emit it as a value, then store it to a temporary slot. |
| Value *V2 = EmitMemory(Arg2T); |
| Arg2 = CreateTemporary(V2->getType()); |
| Builder.CreateStore(V2, Arg2); |
| } else { |
| // If the target has aggregate valists, then the second argument |
| // from GCC is the address of the source valist and we don't |
| // need to do anything special. |
| Arg2 = EmitMemory(Arg2T); |
| } |
| |
| static Type *VPTy = Type::getInt8PtrTy(Context); |
| |
| // FIXME: This ignores alignment and volatility of the arguments. |
| SmallVector<Value *, 2> Args; |
| Args.push_back(Builder.CreateBitCast(Arg1, VPTy)); |
| Args.push_back(Builder.CreateBitCast(Arg2, VPTy)); |
| |
| Builder.CreateCall( |
| Intrinsic::getDeclaration(TheModule, Intrinsic::vacopy), Args); |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinAdjustTrampoline(gimple stmt, Value * &Result) { |
| if (!validate_gimple_arglist(stmt, POINTER_TYPE, VOID_TYPE)) |
| return false; |
| |
| Function *Intr = |
| Intrinsic::getDeclaration(TheModule, Intrinsic::adjust_trampoline); |
| Value *Arg = Builder.CreateBitCast(EmitRegister(gimple_call_arg(stmt, 0)), |
| Builder.getInt8PtrTy()); |
| Result = Builder.CreateCall(Intr, Arg); |
| return true; |
| } |
| |
| bool TreeToLLVM::EmitBuiltinInitTrampoline(gimple stmt, |
| Value * &/*Result*/) { |
| if (!validate_gimple_arglist(stmt, POINTER_TYPE, POINTER_TYPE, |
| POINTER_TYPE, VOID_TYPE)) |
| return false; |
| |
| Value *Tramp = EmitRegister(gimple_call_arg(stmt, 0)); |
| Value *Func = EmitRegister(gimple_call_arg(stmt, 1)); |
| Value *Chain = EmitRegister(gimple_call_arg(stmt, 2)); |
| |
| Type *VPTy = Builder.getInt8PtrTy(); |
| Value *Ops[3] = { Builder.CreateBitCast(Tramp, VPTy), |
| Builder.CreateBitCast(Func, VPTy), |
| Builder.CreateBitCast(Chain, VPTy) }; |
| |
| Function *Intr = |
| Intrinsic::getDeclaration(TheModule, Intrinsic::init_trampoline); |
| Builder.CreateCall(Intr, Ops); |
| return true; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // ... Complex Math Expressions ... |
| //===----------------------------------------------------------------------===// |
| |
| Value *TreeToLLVM::CreateComplex(Value * Real, Value * Imag) { |
| assert(Real->getType() == Imag->getType() && "Component type mismatch!"); |
| Type *EltTy = Real->getType(); |
| Value *Result = UndefValue::get(StructType::get(EltTy, EltTy, NULL)); |
| Result = Builder.CreateInsertValue(Result, Real, 0); |
| Result = Builder.CreateInsertValue(Result, Imag, 1); |
| return Result; |
| } |
| |
| void TreeToLLVM::SplitComplex(Value * Complex, Value * &Real, |
| Value * &Imag) { |
| Real = Builder.CreateExtractValue(Complex, 0); |
| Imag = Builder.CreateExtractValue(Complex, 1); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // ... L-Value Expressions ... |
| //===----------------------------------------------------------------------===// |
| |
| Value *TreeToLLVM::EmitFieldAnnotation(Value * FieldPtr, tree FieldDecl) { |
| tree AnnotateAttr = |
| lookup_attribute("annotate", DECL_ATTRIBUTES(FieldDecl)); |
| |
| Type *SBP = Type::getInt8PtrTy(Context); |
| |
| Function *An = |
| Intrinsic::getDeclaration(TheModule, Intrinsic::ptr_annotation, SBP); |
| |
| // Get file and line number. FIXME: Should this be for the decl or the |
| // use. Is there a location info for the use? |
| Constant *LineNo = ConstantInt::get(Type::getInt32Ty(Context), |
| DECL_SOURCE_LINE(FieldDecl)); |
| Constant *File = ConvertMetadataStringToGV(DECL_SOURCE_FILE(FieldDecl)); |
| |
| File = TheFolder->CreateBitCast(File, SBP); |
| |
| // There may be multiple annotate attributes. Pass return of lookup_attr |
| // to successive lookups. |
| while (AnnotateAttr) { |
| // Each annotate attribute is a tree list. |
| // Get value of list which is our linked list of args. |
| tree args = TREE_VALUE(AnnotateAttr); |
| |
| // Each annotate attribute may have multiple args. |
| // Treat each arg as if it were a separate annotate attribute. |
| for (tree a = args; a; a = TREE_CHAIN(a)) { |
| // Each element of the arg list is a tree list, so get value |
| tree val = TREE_VALUE(a); |
| |
| // Assert its a string, and then get that string. |
| assert(isa<STRING_CST>(val) && |
| "Annotate attribute arg should always be a string"); |
| |
| Constant *strGV = AddressOf(val); |
| |
| // We can not use the IRBuilder because it will constant fold away |
| // the GEP that is critical to distinguish between an annotate |
| // attribute on a whole struct from one on the first element of the |
| // struct. |
| BitCastInst *CastFieldPtr = |
| new BitCastInst(FieldPtr, SBP, FieldPtr->getName()); |
| Builder.Insert(CastFieldPtr); |
| |
| Value *Ops[4] = { CastFieldPtr, Builder.CreateBitCast(strGV, SBP), |
| File, LineNo }; |
| |
| Type *FieldPtrType = FieldPtr->getType(); |
| FieldPtr = Builder.CreateCall(An, Ops); |
| FieldPtr = Builder.CreateBitCast(FieldPtr, FieldPtrType); |
| } |
| |
| // Get next annotate attribute. |
| AnnotateAttr = TREE_CHAIN(AnnotateAttr); |
| if (AnnotateAttr) |
| AnnotateAttr = lookup_attribute("annotate", AnnotateAttr); |
| } |
| return FieldPtr; |
| } |
| |
| LValue TreeToLLVM::EmitLV_ARRAY_REF(tree exp) { |
| // The result type is an ElementTy* in the case of an ARRAY_REF, an array |
| // of ElementTy in the case of ARRAY_RANGE_REF. |
| |
| tree Array = TREE_OPERAND(exp, 0); |
| tree ArrayTreeType = TREE_TYPE(Array); |
| tree Index = TREE_OPERAND(exp, 1); |
| tree IndexType = TREE_TYPE(Index); |
| tree ElementType = TREE_TYPE(ArrayTreeType); |
| |
| assert(isa<ARRAY_TYPE>(ArrayTreeType) && "Unknown ARRAY_REF!"); |
| |
| Value *ArrayAddr; |
| unsigned ArrayAlign; |
| |
| // First subtract the lower bound, if any, in the type of the index. |
| Value *IndexVal = EmitRegister(Index); |
| tree LowerBound = array_ref_low_bound(exp); |
| if (!integer_zerop(LowerBound)) |
| IndexVal = Builder.CreateSub( |
| IndexVal, EmitRegisterWithCast(LowerBound, IndexType), "", |
| hasNUW(TREE_TYPE(Index)), hasNSW(TREE_TYPE(Index))); |
| |
| LValue ArrayAddrLV = EmitLV(Array); |
| assert(!ArrayAddrLV.isBitfield() && "Arrays cannot be bitfields!"); |
| ArrayAddr = ArrayAddrLV.Ptr; |
| ArrayAlign = ArrayAddrLV.getAlignment(); |
| |
| Type *IntPtrTy = getDataLayout().getIntPtrType(ArrayAddr->getType()); |
| IndexVal = Builder.CreateIntCast(IndexVal, IntPtrTy, |
| /*isSigned*/ !TYPE_UNSIGNED(IndexType)); |
| |
| // If we are indexing over a fixed-size type, just use a GEP. |
| if (isSizeCompatible(ElementType)) { |
| // Avoid any assumptions about how the array type is represented in LLVM by |
| // doing the GEP on a pointer to the first array element. |
| Type *EltTy = ConvertType(ElementType); |
| ArrayAddr = Builder.CreateBitCast(ArrayAddr, EltTy->getPointerTo()); |
| StringRef GEPName = flag_verbose_asm ? "ar" : ""; |
| Value *Ptr = POINTER_TYPE_OVERFLOW_UNDEFINED |
| ? Builder.CreateInBoundsGEP(ArrayAddr, IndexVal, GEPName) |
| : Builder.CreateGEP(ArrayAddr, IndexVal, GEPName); |
| unsigned Alignment = |
| MinAlign(ArrayAlign, DL.getABITypeAlignment(EltTy)); |
| return LValue( |
| Builder.CreateBitCast( |
| Ptr, PointerType::getUnqual(ConvertType(TREE_TYPE(exp)))), |
| Alignment); |
| } |
| |
| // Otherwise, just do raw, low-level pointer arithmetic. FIXME: this could be |
| // much nicer in cases like: |
| // float foo(int w, float A[][w], int g) { return A[g][0]; } |
| |
| if (isa<VOID_TYPE>(TREE_TYPE(ArrayTreeType))) { |
| ArrayAddr = |
| Builder.CreateBitCast(ArrayAddr, Type::getInt8PtrTy(Context)); |
| StringRef GEPName = flag_verbose_asm ? "va" : ""; |
| ArrayAddr = POINTER_TYPE_OVERFLOW_UNDEFINED |
| ? Builder.CreateInBoundsGEP(ArrayAddr, IndexVal, GEPName) |
| : Builder.CreateGEP(ArrayAddr, IndexVal, GEPName); |
| return LValue(ArrayAddr, 1); |
| } |
| |
| // FIXME: Might also get here if the element type has constant size, but is |
| // humongous. Add support for this case. |
| assert(TREE_OPERAND(exp, 3) && |
| "Size missing for variable sized element!"); |
| // ScaleFactor is the size of the element type in units divided by (exactly) |
| // TYPE_ALIGN_UNIT(ElementType). |
| Value *ScaleFactor = Builder.CreateIntCast( |
| EmitRegister(TREE_OPERAND(exp, 3)), IntPtrTy, /*isSigned*/ false); |
| assert(isPowerOf2_32(TYPE_ALIGN(ElementType)) && |
| "Alignment not a power of two!"); |
| assert(TYPE_ALIGN(ElementType) >= 8 && |
| "Unit size not a multiple of 8 bits!"); |
| // ScaleType is chosen to correct for the division in ScaleFactor. |
| Type *ScaleType = IntegerType::get(Context, TYPE_ALIGN(ElementType)); |
| ArrayAddr = Builder.CreateBitCast(ArrayAddr, ScaleType->getPointerTo()); |
| |
| IndexVal = Builder.CreateMul(IndexVal, ScaleFactor); |
| unsigned Alignment = MinAlign(ArrayAlign, TYPE_ALIGN(ElementType) / 8); |
| StringRef GEPName = flag_verbose_asm ? "ra" : ""; |
| Value *Ptr = POINTER_TYPE_OVERFLOW_UNDEFINED |
| ? Builder.CreateInBoundsGEP(ArrayAddr, IndexVal, GEPName) |
| : Builder.CreateGEP(ArrayAddr, IndexVal, GEPName); |
| return LValue( |
| Builder.CreateBitCast( |
| Ptr, PointerType::getUnqual(ConvertType(TREE_TYPE(exp)))), |
| Alignment); |
| } |
| |
| LValue TreeToLLVM::EmitLV_BIT_FIELD_REF(tree exp) { |
| LValue Ptr = EmitLV(TREE_OPERAND(exp, 0)); |
| assert(!Ptr.isBitfield() && |
| "BIT_FIELD_REF operands cannot be bitfields!"); |
| |
| unsigned BitStart = (unsigned) TREE_INT_CST_LOW(TREE_OPERAND(exp, 2)); |
| unsigned BitSize = (unsigned) TREE_INT_CST_LOW(TREE_OPERAND(exp, 1)); |
| Type *ValTy = ConvertType(TREE_TYPE(exp)); |
| |
| unsigned ValueSizeInBits = DL.getTypeSizeInBits(ValTy); |
| assert(BitSize <= ValueSizeInBits && |
| "ValTy isn't large enough to hold the value loaded!"); |
| |
| assert(ValueSizeInBits == DL.getTypeAllocSizeInBits(ValTy) && |
| "FIXME: BIT_FIELD_REF logic is broken for non-round types"); |
| |
| // BIT_FIELD_REF values can have BitStart values that are quite large. We |
| // know that the thing we are loading is ValueSizeInBits large. If BitStart |
| // is larger than ValueSizeInBits, bump the pointer over to where it should |
| // be. |
| if (unsigned UnitOffset = BitStart / ValueSizeInBits) { |
| // TODO: If Ptr.Ptr is a struct type or something, we can do much better |
| // than this. e.g. check out when compiling unwind-dw2-fde-darwin.c. |
| Ptr.Ptr = Builder.CreateBitCast(Ptr.Ptr, ValTy->getPointerTo()); |
| Ptr.Ptr = Builder.CreateGEP(Ptr.Ptr, Builder.getInt32(UnitOffset), |
| flag_verbose_asm ? "bfr" : ""); |
| unsigned OctetOffset = (UnitOffset * ValueSizeInBits) / 8; |
| Ptr.setAlignment(MinAlign(Ptr.getAlignment(), OctetOffset)); |
| BitStart -= UnitOffset * ValueSizeInBits; |
| } |
| |
| // If this is referring to the whole field, return the whole thing. |
| if (BitStart == 0 && BitSize == ValueSizeInBits) { |
| return LValue(Builder.CreateBitCast(Ptr.Ptr, ValTy->getPointerTo()), |
| Ptr.getAlignment()); |
| } |
| |
| return LValue(Builder.CreateBitCast(Ptr.Ptr, ValTy->getPointerTo()), 1, |
| BitStart, BitSize); |
| } |
| |
| LValue TreeToLLVM::EmitLV_COMPONENT_REF(tree exp) { |
| LValue StructAddrLV = EmitLV(TREE_OPERAND(exp, 0)); |
| tree FieldDecl = TREE_OPERAND(exp, 1); |
| unsigned LVAlign = StructAddrLV.getAlignment(); |
| |
| assert(isa<RECORD_OR_UNION_TYPE>(DECL_CONTEXT(FieldDecl))); |
| |
| Type *StructTy = ConvertType(DECL_CONTEXT(FieldDecl)); |
| |
| assert((!StructAddrLV.isBitfield() || StructAddrLV.BitStart == 0) && |
| "structs cannot be bitfields!"); |
| |
| StructAddrLV.Ptr = |
| Builder.CreateBitCast(StructAddrLV.Ptr, StructTy->getPointerTo()); |
| Type *FieldTy = ConvertType(TREE_TYPE(FieldDecl)); |
| |
| // BitStart - This is the actual offset of the field from the start of the |
| // struct, in bits. For bitfields this may be on a non-byte boundary. |
| uint64_t FieldBitOffset = |
| getInt64(DECL_FIELD_BIT_OFFSET(FieldDecl), true); |
| unsigned BitStart; |
| Value *FieldPtr; |
| |
| // If the GCC field directly corresponds to an LLVM field, handle it. |
| unsigned MemberIndex = GetFieldIndex(FieldDecl, StructTy); |
| if (MemberIndex < INT_MAX) { |
| assert(!TREE_OPERAND(exp, 2) && "Constant not gimple min invariant?"); |
| // Get a pointer to the byte in which the GCC field starts. |
| FieldPtr = Builder.CreateStructGEP(StructAddrLV.Ptr, MemberIndex, |
| flag_verbose_asm ? "cr" : ""); |
| // Within that byte, the bit at which the GCC field starts. |
| BitStart = FieldBitOffset & 7; |
| } else { |
| // Offset will hold the field offset in octets. |
| Value *Offset; |
| |
| if (TREE_OPERAND(exp, 2)) { |
| Offset = EmitRegister(TREE_OPERAND(exp, 2)); |
| // At this point the offset is measured in units divided by (exactly) |
| // (DECL_OFFSET_ALIGN / BITS_PER_UNIT). Convert to octets. |
| unsigned factor = DECL_OFFSET_ALIGN(FieldDecl) / 8; |
| if (factor != 1) |
| Offset = Builder.CreateMul( |
| Offset, ConstantInt::get(Offset->getType(), factor)); |
| } else { |
| assert(DECL_FIELD_OFFSET(FieldDecl) && "Field offset not available!"); |
| Offset = EmitRegister(DECL_FIELD_OFFSET(FieldDecl)); |
| // At this point the offset is measured in units. Convert to octets. |
| unsigned factor = BITS_PER_UNIT / 8; |
| if (factor != 1) |
| Offset = Builder.CreateMul( |
| Offset, ConstantInt::get(Offset->getType(), factor)); |
| } |
| |
| // Here BitStart gives the offset of the field in bits from Offset. |
| BitStart = FieldBitOffset; |
| |
| // Incorporate as much of it as possible into the pointer computation. |
| unsigned ByteOffset = BitStart / 8; |
| if (ByteOffset > 0) { |
| Offset = Builder.CreateAdd( |
| Offset, ConstantInt::get(Offset->getType(), ByteOffset)); |
| BitStart -= ByteOffset * 8; |
| } |
| |
| Type *BytePtrTy = Type::getInt8PtrTy(Context); |
| FieldPtr = Builder.CreateBitCast(StructAddrLV.Ptr, BytePtrTy); |
| FieldPtr = Builder.CreateInBoundsGEP(FieldPtr, Offset, |
| flag_verbose_asm ? "rc" : ""); |
| FieldPtr = Builder.CreateBitCast(FieldPtr, FieldTy->getPointerTo()); |
| } |
| |
| // Compute the alignment of the octet containing the first bit of the field, |
| // without assuming that the containing struct itself is properly aligned. |
| LVAlign = MinAlign(LVAlign, getFieldAlignment(FieldDecl)); |
| |
| // If the FIELD_DECL has an annotate attribute on it, emit it. |
| if (lookup_attribute("annotate", DECL_ATTRIBUTES(FieldDecl))) |
| FieldPtr = EmitFieldAnnotation(FieldPtr, FieldDecl); |
| |
| // Make sure we return a pointer to the right type. |
| Type *EltTy = ConvertType(TREE_TYPE(exp)); |
| FieldPtr = Builder.CreateBitCast(FieldPtr, EltTy->getPointerTo()); |
| |
| if (!isBitfield(FieldDecl)) { |
| assert(BitStart == 0 && "Not a bitfield but not at a byte offset!"); |
| return LValue(FieldPtr, LVAlign); |
| } |
| |
| assert(BitStart < 8 && |
| "Bit offset not properly incorporated in the pointer"); |
| assert(DECL_SIZE(FieldDecl) && isa<INTEGER_CST>(DECL_SIZE(FieldDecl)) && |
| "Variable sized bitfield?"); |
| unsigned BitfieldSize = TREE_INT_CST_LOW(DECL_SIZE(FieldDecl)); |
| return LValue(FieldPtr, LVAlign, BitStart, BitfieldSize); |
| } |
| |
| LValue TreeToLLVM::EmitLV_DECL(tree exp) { |
| Value *Decl = DEFINITION_LOCAL(exp); |
| if (Decl == 0) { |
| if (errorcount || sorrycount) { |
| Type *Ty = ConvertType(TREE_TYPE(exp)); |
| PointerType *PTy = Ty->getPointerTo(); |
| LValue LV(ConstantPointerNull::get(PTy), 1); |
| return LV; |
| } |
| debug_tree(exp); |
| llvm_unreachable("Referencing decl that hasn't been laid out!"); |
| } |
| |
| Type *Ty = ConvertType(TREE_TYPE(exp)); |
| // If we have "extern void foo", make the global have type {} instead of |
| // type void. |
| if (Ty->isVoidTy()) |
| Ty = StructType::get(Context); |
| PointerType *PTy = Ty->getPointerTo(); |
| unsigned Alignment = DECL_ALIGN(exp) / 8; |
| if (!Alignment) |
| Alignment = 1; |
| |
| return LValue(Builder.CreateBitCast(Decl, PTy), Alignment); |
| } |
| |
| LValue TreeToLLVM::EmitLV_INDIRECT_REF(tree exp) { |
| // The lvalue is just the address. |
| LValue LV = |
| LValue(EmitRegister(TREE_OPERAND(exp, 0)), expr_align(exp) / 8); |
| // May need to change pointer type, for example when INDIRECT_REF is applied |
| // to a void*, resulting in a non-void type. |
| LV.Ptr = Builder |
| .CreateBitCast(LV.Ptr, ConvertType(TREE_TYPE(exp))->getPointerTo()); |
| return LV; |
| } |
| |
| #if (GCC_MINOR > 5) |
| LValue TreeToLLVM::EmitLV_MEM_REF(tree exp) { |
| // The address is the first operand offset in bytes by the second. |
| Value *Addr = EmitRegister(TREE_OPERAND(exp, 0)); |
| if (!integer_zerop(TREE_OPERAND(exp, 1))) { |
| // Convert to a byte pointer and displace by the offset. |
| Addr = Builder.CreateBitCast(Addr, GetUnitPointerType(Context)); |
| APInt Offset = getAPIntValue(TREE_OPERAND(exp, 1)); |
| // The address is always inside the referenced object, so "inbounds". |
| Addr = |
| Builder.CreateInBoundsGEP(Addr, ConstantInt::get(Context, Offset), |
| flag_verbose_asm ? "mrf" : ""); |
| } |
| |
| // Ensure the pointer has the right type. |
| Addr = Builder.CreateBitCast(Addr, getPointerToType(TREE_TYPE(exp))); |
| |
| unsigned Alignment = |
| #if (GCC_MINOR < 6) |
| get_object_alignment(exp, TYPE_ALIGN(TREE_TYPE(exp)), |
| BIGGEST_ALIGNMENT); |
| #elif(GCC_MINOR < 7) |
| std::max(get_object_alignment(exp, BIGGEST_ALIGNMENT), |
| TYPE_ALIGN(TREE_TYPE(exp))); |
| #elif (GCC_MINOR < 8) |
| get_object_or_type_alignment(exp); |
| #else |
| get_object_alignment(exp); |
| #endif |
| bool Volatile = TREE_THIS_VOLATILE(exp); |
| |
| return LValue(Addr, Alignment / 8, Volatile); |
| } |
| #endif |
| |
| #if (GCC_MINOR < 6) |
| LValue TreeToLLVM::EmitLV_MISALIGNED_INDIRECT_REF(tree exp) { |
| // The lvalue is just the address. The alignment is given by operand 1. |
| unsigned Alignment = tree_low_cst(TREE_OPERAND(exp, 1), true); |
| // The alignment need not be a power of two, so replace it with the largest |
| // power of two that divides it. |
| Alignment &= -Alignment; |
| if (!Alignment) |
| Alignment = 8; |
| assert(!(Alignment & 7) && "Alignment not in octets!"); |
| LValue LV = LValue(EmitRegister(TREE_OPERAND(exp, 0)), Alignment / 8); |
| // May need to change pointer type, for example when MISALIGNED_INDIRECT_REF |
| // is applied to a void*, resulting in a non-void type. |
| LV.Ptr = Builder |
| .CreateBitCast(LV.Ptr, ConvertType(TREE_TYPE(exp))->getPointerTo()); |
| return LV; |
| } |
| #endif |
| |
| LValue TreeToLLVM::EmitLV_VIEW_CONVERT_EXPR(tree exp) { |
| // The address is the address of the operand. |
| LValue LV = EmitLV(TREE_OPERAND(exp, 0)); |
| // The type is the type of the expression. |
| LV.Ptr = Builder |
| .CreateBitCast(LV.Ptr, ConvertType(TREE_TYPE(exp))->getPointerTo()); |
| return LV; |
| } |
| |
| LValue TreeToLLVM::EmitLV_WITH_SIZE_EXPR(tree exp) { |
| // The address is the address of the operand. |
| return EmitLV(TREE_OPERAND(exp, 0)); |
| } |
| |
| LValue TreeToLLVM::EmitLV_XXXXPART_EXPR(tree exp, unsigned Idx) { |
| LValue Ptr = EmitLV(TREE_OPERAND(exp, 0)); |
| assert(!Ptr.isBitfield() && |
| "REALPART_EXPR / IMAGPART_EXPR operands cannot be bitfields!"); |
| unsigned Alignment; |
| if (Idx == 0) |
| // REALPART alignment is same as the complex operand. |
| Alignment = Ptr.getAlignment(); |
| else |
| // IMAGPART alignment = MinAlign(Ptr.Alignment, sizeof field); |
| Alignment = MinAlign(Ptr.getAlignment(), |
| DL.getTypeAllocSize(Ptr.Ptr->getType())); |
| return LValue(Builder.CreateStructGEP(Ptr.Ptr, Idx, |
| flag_verbose_asm ? "prtxpr" : ""), |
| Alignment); |
| } |
| |
| LValue TreeToLLVM::EmitLV_SSA_NAME(tree exp) { |
| // TODO: Check the ssa name is being used as an rvalue, see EmitLoadOfLValue. |
| Value *Temp = CreateTemporary(ConvertType(TREE_TYPE(exp))); |
| Builder.CreateStore(EmitReg_SSA_NAME(exp), Temp); |
| return LValue(Temp, 1); |
| } |
| |
| LValue TreeToLLVM::EmitLV_TARGET_MEM_REF(tree exp) { |
| // TODO: Take the address space into account. |
| |
| Value *Addr; |
| Value *Delta = 0; // Offset from base pointer in units |
| #if (GCC_MINOR > 5) |
| // Starting with gcc 4.6 the address is base + index * step + index2 + offset. |
| Addr = EmitRegister(TMR_BASE(exp)); |
| if (TMR_INDEX2(exp) && !integer_zerop(TMR_INDEX2(exp))) |
| Delta = EmitRegister(TMR_INDEX2(exp)); |
| #else |
| // In gcc 4.5 the address is &symbol + base + index * step + offset. |
| if (TMR_SYMBOL(exp)) { |
| Addr = EmitLV(TMR_SYMBOL(exp)).Ptr; |
| if (TMR_BASE(exp) && !integer_zerop(TMR_BASE(exp))) |
| Delta = EmitRegister(TMR_BASE(exp)); |
| } else { |
| assert(TMR_BASE(exp) && "TARGET_MEM_REF has neither base nor symbol!"); |
| Addr = EmitRegister(TMR_BASE(exp)); |
| // The type of BASE is sizetype or a pointer type. Convert sizetype to i8*. |
| if (!isa<PointerType>(Addr->getType())) |
| Addr = Builder.CreateIntToPtr(Addr, GetUnitPointerType(Context)); |
| } |
| #endif |
| |
| if (TMR_INDEX(exp)) { |
| Value *Index = EmitRegister(TMR_INDEX(exp)); |
| if (TMR_STEP(exp) && !integer_onep(TMR_STEP(exp))) |
| Index = Builder.CreateMul(Index, EmitRegisterConstant(TMR_STEP(exp))); |
| Delta = Delta ? Builder.CreateAdd(Delta, Index) : Index; |
| } |
| |
| if (TMR_OFFSET(exp) && !integer_zerop(TMR_OFFSET(exp))) { |
| Constant *Off = |
| ConstantInt::get(Context, getAPIntValue(TMR_OFFSET(exp))); |
| Delta = Delta ? Builder.CreateAdd(Delta, Off) : Off; |
| } |
| |
| if (Delta) { |
| // Advance the base pointer by the given number of units. |
| Addr = Builder.CreateBitCast(Addr, GetUnitPointerType(Context)); |
| StringRef GEPName = flag_verbose_asm ? "" : "tmrf"; |
| Addr = POINTER_TYPE_OVERFLOW_UNDEFINED |
| ? Builder.CreateInBoundsGEP(Addr, Delta, GEPName) |
| : Builder.CreateGEP(Addr, Delta, GEPName); |
| } |
| |
| // The result can be of a different pointer type even if we didn't advance it. |
| Addr = Builder.CreateBitCast(Addr, getPointerToType(TREE_TYPE(exp))); |
| unsigned Alignment = |
| #if (GCC_MINOR < 6) |
| get_object_alignment(exp, TYPE_ALIGN(TREE_TYPE(exp)), |
| BIGGEST_ALIGNMENT); |
| #elif(GCC_MINOR < 7) |
| std::max(get_object_alignment(exp, BIGGEST_ALIGNMENT), |
| TYPE_ALIGN(TREE_TYPE(exp))); |
| #elif (GCC_MINOR < 8) |
| get_object_or_type_alignment(exp); |
| #else |
| get_object_alignment(exp); |
| #endif |
| bool Volatile = TREE_THIS_VOLATILE(exp); |
| |
| return LValue(Addr, Alignment / 8, Volatile); |
| } |
| |
| Constant *TreeToLLVM::AddressOfLABEL_DECL(tree exp) { |
| return BlockAddress::get(Fn, getLabelDeclBlock(exp)); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // ... Emit helpers ... |
| //===----------------------------------------------------------------------===// |
| |
| /// EmitMinInvariant - The given value is constant in this function. Return the |
| /// corresponding LLVM value. Only creates code in the entry block. |
| Value *TreeToLLVM::EmitMinInvariant(tree reg) { |
| Value *V = isa<ADDR_EXPR>(reg) ? EmitInvariantAddress(reg) |
| : EmitRegisterConstant(reg); |
| assert(V->getType() == getRegType(TREE_TYPE(reg)) && |
| "Gimple min invariant has wrong type!"); |
| return V; |
| } |
| |
| /// EmitInvariantAddress - The given address is constant in this function. |
| /// Return the corresponding LLVM value. Only creates code in the entry block. |
| Value *TreeToLLVM::EmitInvariantAddress(tree addr) { |
| assert(is_gimple_invariant_address(addr) && |
| "Expected a locally constant address!"); |
| assert(is_gimple_reg_type(TREE_TYPE(addr)) && "Not of register type!"); |
| |
| // Any generated code goes in the entry block. |
| BasicBlock *EntryBlock = Fn->begin(); |
| |
| // Note the current builder position. |
| BasicBlock *SavedInsertBB = Builder.GetInsertBlock(); |
| BasicBlock::iterator SavedInsertPoint = Builder.GetInsertPoint(); |
| |
| // Pop the entry block terminator. There may not be a terminator if we are |
| // recursing or if the entry block was not yet finished. |
| Instruction *Terminator = EntryBlock->getTerminator(); |
| assert(((SavedInsertBB != EntryBlock && Terminator) || |
| (SavedInsertPoint == EntryBlock->end() && !Terminator)) && |
| "Insertion point doesn't make sense!"); |
| if (Terminator) |
| Terminator->removeFromParent(); |
| |
| // Point the builder at the end of the entry block. |
| Builder.SetInsertPoint(EntryBlock); |
| |
| // Calculate the address. |
| assert(isa<ADDR_EXPR>(addr) && "Invariant address not ADDR_EXPR!"); |
| Value *Address = EmitADDR_EXPR(addr); |
| |
| // Restore the entry block terminator. |
| if (Terminator) |
| EntryBlock->getInstList().push_back(Terminator); |
| |
| // Restore the builder insertion point. |
| if (SavedInsertBB != EntryBlock) |
| Builder.SetInsertPoint(SavedInsertBB, SavedInsertPoint); |
| |
| assert(Address->getType() == getRegType(TREE_TYPE(addr)) && |
| "Invariant address has wrong type!"); |
| return Address; |
| } |
| |
| /// EmitRegisterConstant - Convert the given global constant of register type to |
| /// an LLVM constant. Creates no code, only constants. |
| Constant *TreeToLLVM::EmitRegisterConstant(tree reg) { |
| #ifndef NDEBUG |
| if (!is_gimple_constant(reg)) { |
| debug_tree(reg); |
| llvm_unreachable("Unsupported gimple!"); |
| } |
| #endif |
| assert(is_gimple_reg_type(TREE_TYPE(reg)) && "Not of register type!"); |
| |
| switch (TREE_CODE(reg)) { |
| default: |
| debug_tree(reg); |
| llvm_unreachable("Unhandled GIMPLE constant!"); |
| |
| case INTEGER_CST: |
| return EmitIntegerRegisterConstant(reg); |
| case REAL_CST: |
| return EmitRealRegisterConstant(reg); |
| //case FIXED_CST: // Fixed point constant - not yet supported. |
| //case STRING_CST: // Allowed by is_gimple_constant, but no known examples. |
| case COMPLEX_CST: |
| return EmitComplexRegisterConstant(reg); |
| case VECTOR_CST: |
| return EmitVectorRegisterConstant(reg); |
| case CONSTRUCTOR: |
| // Vector constant constructors are gimple invariant. See GCC testcase |
| // pr34856.c for an example. |
| return EmitConstantVectorConstructor(reg); |
| } |
| } |
| |
| /// EmitRegisterConstantWithCast - Utility that casts the value returned by |
| /// EmitRegisterConstant to the given register type. |
| Constant *TreeToLLVM::EmitRegisterConstantWithCast(tree reg, tree type) { |
| Constant *C = EmitRegisterConstant(reg); |
| if (TREE_TYPE(reg) == type) |
| return C; |
| // For vector types, TYPE_UNSIGNED returns the unsignedness of the element. |
| bool SrcIsSigned = !TYPE_UNSIGNED(TREE_TYPE(reg)); |
| bool DstIsSigned = !TYPE_UNSIGNED(type); |
| return CastToAnyType(C, SrcIsSigned, getRegType(type), DstIsSigned); |
| } |
| |
| /// EncodeExpr - Write the given expression into Buffer as it would appear in |
| /// memory on the target (the buffer is resized to contain exactly the bytes |
| /// written). Return the number of bytes written; this can also be obtained |
| /// by querying the buffer's size. |
| /// The following kinds of expressions are currently supported: INTEGER_CST, |
| /// REAL_CST, COMPLEX_CST, VECTOR_CST, STRING_CST. |
| static unsigned EncodeExpr(tree exp, |
| SmallVectorImpl<unsigned char> & Buffer) { |
| const tree type = TREE_TYPE(exp); |
| unsigned SizeInBytes = (TREE_INT_CST_LOW(TYPE_SIZE(type)) + 7) / 8; |
| Buffer.resize(SizeInBytes); |
| unsigned BytesWritten = native_encode_expr(exp, &Buffer[0], SizeInBytes); |
| assert(BytesWritten == SizeInBytes && |
| "Failed to fully encode expression!"); |
| return BytesWritten; |
| } |
| |
| /// EmitComplexRegisterConstant - Turn the given COMPLEX_CST into an LLVM |
| /// constant of the corresponding register type. |
| Constant *TreeToLLVM::EmitComplexRegisterConstant(tree reg) { |
| tree elt_type = TREE_TYPE(TREE_TYPE(reg)); |
| Constant *Elts[2] = { |
| EmitRegisterConstantWithCast(TREE_REALPART(reg), elt_type), |
| EmitRegisterConstantWithCast(TREE_IMAGPART(reg), elt_type) |
| }; |
| return ConstantStruct::getAnon(Elts); |
| } |
| |
| /// EmitIntegerRegisterConstant - Turn the given INTEGER_CST into an LLVM |
| /// constant of the corresponding register type. |
| Constant *TreeToLLVM::EmitIntegerRegisterConstant(tree reg) { |
| ConstantInt *CI = ConstantInt::get(Context, getAPIntValue(reg)); |
| // The destination can be a pointer, integer or floating point type so we need |
| // a generalized cast here |
| Type *Ty = getRegType(TREE_TYPE(reg)); |
| Instruction::CastOps opcode = CastInst::getCastOpcode( |
| CI, false, Ty, !TYPE_UNSIGNED(TREE_TYPE(reg))); |
| return TheFolder->CreateCast(opcode, CI, Ty); |
| } |
| |
| /// EmitRealRegisterConstant - Turn the given REAL_CST into an LLVM constant |
| /// of the corresponding register type. |
| Constant *TreeToLLVM::EmitRealRegisterConstant(tree reg) { |
| // TODO: Rather than going through memory, construct the APFloat directly from |
| // the real_value. This works fine for zero, inf and nan values, but APFloat |
| // has no constructor for normal numbers, i.e. constructing a normal number |
| // from the exponent and significand. |
| // TODO: Test implementation on a big-endian machine. |
| |
| // Encode the constant in Buffer in target format. |
| SmallVector<unsigned char, 16> Buffer; |
| EncodeExpr(reg, Buffer); |
| |
| // Discard any alignment padding, which we assume comes at the end. |
| unsigned Precision = TYPE_PRECISION(TREE_TYPE(reg)); |
| assert((Precision & 7) == 0 && "Unsupported real number precision!"); |
| Buffer.resize(Precision / 8); |
| |
| // We are going to view the buffer as an array of APInt words. Ensure that |
| // the buffer contains a whole number of words by extending it if necessary. |
| unsigned Words = (Precision + integerPartWidth - 1) / integerPartWidth; |
| // On a little-endian machine extend the buffer by adding bytes to the end. |
| Buffer.resize(Words * (integerPartWidth / 8)); |
| // On a big-endian machine extend the buffer by adding bytes to the beginning. |
| if (BYTES_BIG_ENDIAN) |
| std::copy_backward(Buffer.begin(), Buffer.begin() + Precision / 8, |
| Buffer.end()); |
| |
| // Ensure that the least significant word comes first: we are going to make an |
| // APInt, and the APInt constructor wants the least significant word first. |
| integerPart *Parts = (integerPart *)&Buffer[0]; |
| if (BYTES_BIG_ENDIAN) |
| std::reverse(Parts, Parts + Words); |
| |
| Type *Ty = getRegType(TREE_TYPE(reg)); |
| if (Ty->isPPC_FP128Ty()) { |
| // This type is actually a pair of doubles in disguise. They turn up the |
| // wrong way round here, so flip them. |
| assert(FLOAT_WORDS_BIG_ENDIAN && "PPC not big endian!"); |
| assert(Words == 2 && Precision == 128 && "Strange size for PPC_FP128!"); |
| std::swap(Parts[0], Parts[1]); |
| } |
| |
| // Form an APInt from the buffer, an APFloat from the APInt, and the desired |
| // floating point constant from the APFloat, phew! |
| const APInt &I = APInt(Precision, Words, Parts); |
| return ConstantFP::get(Context, APFloat(Ty->getFltSemantics(), I)); |
| } |
| |
| /// EmitConstantVectorConstructor - Turn the given constant CONSTRUCTOR into |
| /// an LLVM constant of the corresponding vector register type. |
| Constant *TreeToLLVM::EmitConstantVectorConstructor(tree reg) { |
| // Get the constructor as an LLVM constant. |
| Constant *C = ConvertInitializer(reg); |
| // Load the vector register out of it. |
| return ExtractRegisterFromConstant(C, TREE_TYPE(reg)); |
| } |
| |
| /// EmitVectorRegisterConstant - Turn the given VECTOR_CST into an LLVM constant |
| /// of the corresponding register type. |
| Constant *TreeToLLVM::EmitVectorRegisterConstant(tree reg) { |
| // If there are no elements then immediately return the default value for a |
| // small speedup. |
| #if (GCC_MINOR < 8) |
| if (!TREE_VECTOR_CST_ELTS(reg)) |
| #else |
| if (!VECTOR_CST_NELTS(reg)) |
| #endif |
| return getDefaultValue(getRegType(TREE_TYPE(reg))); |
| |
| // Convert the elements. |
| SmallVector<Constant *, 16> Elts; |
| tree elt_type = TREE_TYPE(TREE_TYPE(reg)); |
| #if (GCC_MINOR < 8) |
| for (tree ch = TREE_VECTOR_CST_ELTS(reg); ch; ch = TREE_CHAIN(ch)) { |
| tree elt = TREE_VALUE(ch); |
| #else |
| for (unsigned i = 0, e = VECTOR_CST_NELTS(reg); i != e; ++i) { |
| tree elt = VECTOR_CST_ELT(reg, i); |
| #endif |
| Elts.push_back(EmitRegisterConstantWithCast(elt, elt_type)); |
| } |
| |
| // If there weren't enough elements then set the rest of the vector to the |
| // default value. |
| if (Elts.size() < TYPE_VECTOR_SUBPARTS(TREE_TYPE(reg))) { |
| Constant *Default = getDefaultValue(getRegType(elt_type)); |
| Elts.append(TYPE_VECTOR_SUBPARTS(TREE_TYPE(reg)) - Elts.size(), |
| Default); |
| } |
| |
| return ConstantVector::get(Elts); |
| } |
| |
| /// VectorHighElements - Return a vector of half the length, consisting of the |
| /// elements of the given vector with indices in the top half. |
| Value *TreeToLLVM::VectorHighElements(Value * Vec) { |
| VectorType *Ty = cast<VectorType>(Vec->getType()); |
| assert(!(Ty->getNumElements() & 1) && |
| "Vector has odd number of elements!"); |
| unsigned NumElts = Ty->getNumElements() / 2; |
| SmallVector<Constant *, 8> Mask; |
| Mask.reserve(NumElts); |
| for (unsigned i = 0; i != NumElts; ++i) |
| Mask.push_back(Builder.getInt32(NumElts + i)); |
| return Builder.CreateShuffleVector(Vec, UndefValue::get(Ty), |
| ConstantVector::get(Mask)); |
| } |
| |
| /// VectorLowElements - Return a vector of half the length, consisting of the |
| /// elements of the given vector with indices in the bottom half. |
| Value *TreeToLLVM::VectorLowElements(Value * Vec) { |
| VectorType *Ty = cast<VectorType>(Vec->getType()); |
| assert(!(Ty->getNumElements() & 1) && |
| "Vector has odd number of elements!"); |
| unsigned NumElts = Ty->getNumElements() / 2; |
| SmallVector<Constant *, 8> Mask; |
| Mask.reserve(NumElts); |
| for (unsigned i = 0; i != NumElts; ++i) |
| Mask.push_back(Builder.getInt32(i)); |
| return Builder.CreateShuffleVector(Vec, UndefValue::get(Ty), |
| ConstantVector::get(Mask)); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // ... EmitReg* - Convert register expression to LLVM... |
| //===----------------------------------------------------------------------===// |
| |
| /// EmitMemory - Convert the specified gimple register or local constant of |
| /// register type to an LLVM value with in-memory type (given by ConvertType). |
| Value *TreeToLLVM::EmitMemory(tree reg) { |
| return Reg2Mem(EmitRegister(reg), TREE_TYPE(reg), Builder); |
| } |
| |
| /// EmitRegister - Convert the specified gimple register or local constant of |
| /// register type to an LLVM value. Only creates code in the entry block. |
| Value *TreeToLLVM::EmitRegister(tree reg) { |
| while (isa<OBJ_TYPE_REF>(reg)) |
| reg = OBJ_TYPE_REF_EXPR(reg); |
| return isa<SSA_NAME>(reg) ? EmitReg_SSA_NAME(reg) : EmitMinInvariant(reg); |
| } |
| |
| /// EmitRegisterWithCast - Utility method that calls EmitRegister, then casts |
| /// the returned value to the given register type. |
| Value *TreeToLLVM::EmitRegisterWithCast(tree reg, tree type) { |
| Value *V = EmitRegister(reg); |
| if (TREE_TYPE(reg) == type) |
| return V; |
| // For vector types, TYPE_UNSIGNED returns the unsignedness of the element. |
| bool SrcIsSigned = !TYPE_UNSIGNED(TREE_TYPE(reg)); |
| bool DstIsSigned = !TYPE_UNSIGNED(type); |
| return CastToAnyType(V, SrcIsSigned, getRegType(type), DstIsSigned); |
| } |
| |
| /// EmitReg_SSA_NAME - Return the defining value of the given SSA_NAME. |
| /// Only creates code in the entry block. |
| Value *TreeToLLVM::EmitReg_SSA_NAME(tree reg) { |
| assert(is_gimple_reg_type(TREE_TYPE(reg)) && "Not of register type!"); |
| |
| // If we already found the definition of the SSA name, return it. |
| if (Value *ExistingValue = SSANames[reg]) { |
| assert(ExistingValue->getType() == getRegType(TREE_TYPE(reg)) && |
| "SSA name has wrong type!"); |
| if (!isSSAPlaceholder(ExistingValue)) |
| return ExistingValue; |
| } |
| |
| // If this is not the definition of the SSA name, return a placeholder value. |
| if (!SSA_NAME_IS_DEFAULT_DEF(reg)) { |
| if (Value *ExistingValue = SSANames[reg]) |
| return ExistingValue; // The type was sanity checked above. |
| return SSANames[reg] = GetSSAPlaceholder(getRegType(TREE_TYPE(reg))); |
| } |
| |
| // This SSA name is the default definition for the underlying symbol. |
| |
| // The underlying symbol is an SSA variable. |
| tree var = SSA_NAME_VAR(reg); |
| assert(SSA_VAR_P(var) && "Not an SSA variable!"); |
| |
| // If the variable is itself an ssa name, use its LLVM value. |
| if (isa<SSA_NAME>(var)) { |
| Value *Val = EmitReg_SSA_NAME(var); |
| assert(Val->getType() == getRegType(TREE_TYPE(reg)) && |
| "SSA name has wrong type!"); |
| return DefineSSAName(reg, Val); |
| } |
| |
| // Otherwise the symbol is a VAR_DECL, PARM_DECL or RESULT_DECL. Since a |
| // default definition is only created if the very first reference to the |
| // variable in the function is a read operation, and refers to the value |
| // read, it has an undefined value for VAR_DECLs (a RESULT_DECL can have |
| // an initial value if the function returns a class by value). |
| assert((isa<PARM_DECL>(var) || isa<RESULT_DECL>(var) || |
| isa<VAR_DECL>(var)) && "Unsupported SSA name definition!"); |
| if (isa<VAR_DECL>(var)) |
| return DefineSSAName(reg, UndefValue::get(getRegType(TREE_TYPE(reg)))); |
| |
| // Read the initial value of the parameter and associate it with the ssa name. |
| assert(DECL_LOCAL_IF_SET(var) != 0 && "Parameter not laid out?"); |
| |
| unsigned Alignment = DECL_ALIGN(var) / 8; |
| assert(Alignment != 0 && "Parameter with unknown alignment!"); |
| |
| // Perform the load in the entry block, after all parameters have been set up |
| // with their initial values, and before any modifications to their values. |
| |
| // Create a builder that inserts code before the SSAInsertionPoint marker. |
| LLVMBuilder SSABuilder(Context, Builder.getFolder()); |
| SSABuilder.SetInsertPoint(SSAInsertionPoint->getParent(), |
| SSAInsertionPoint); |
| |
| // Use it to load the parameter value. |
| MemRef ParamLoc(DECL_LOCAL_IF_SET(var), Alignment, false); |
| Value *Def = |
| LoadRegisterFromMemory(ParamLoc, TREE_TYPE(reg), 0, SSABuilder); |
| |
| if (flag_verbose_asm) |
| NameValue(Def, reg); |
| return DefineSSAName(reg, Def); |
| } |
| |
| // Unary expressions. |
| Value *TreeToLLVM::EmitReg_ABS_EXPR(tree op) { |
| if (!isa<FLOAT_TYPE>(TREE_TYPE(op))) { |
| Value *Op = EmitRegister(op); |
| Value *OpN = Builder.CreateNeg(Op, Op->getName() + "neg"); |
| ICmpInst::Predicate pred = |
| TYPE_UNSIGNED(TREE_TYPE(op)) ? ICmpInst::ICMP_UGE |
| : ICmpInst::ICMP_SGE; |
| Value *Cmp = Builder.CreateICmp( |
| pred, Op, Constant::getNullValue(Op->getType()), "abscond"); |
| return Builder.CreateSelect(Cmp, Op, OpN, Op->getName() + "abs"); |
| } |
| |
| if (isa<VECTOR_TYPE>(TREE_TYPE(op))) { |
| // Clear the sign bits. |
| Value *Op = EmitRegister(op); |
| VectorType *VecTy = cast<VectorType>(Op->getType()); |
| |
| // Mask = ~(1 << (Bits-1)). |
| unsigned Bits = VecTy->getElementType()->getPrimitiveSizeInBits(); |
| Type *IntTy = IntegerType::get(Context, Bits); |
| Type *IntVecTy = VectorType::get(IntTy, VecTy->getNumElements()); |
| APInt API = APInt::getAllOnesValue(Bits); |
| API.clearBit(Bits - 1); |
| Constant *Mask = ConstantInt::get(IntVecTy, API); |
| |
| // Zap the sign bits. |
| Op = Builder.CreateBitCast(Op, IntVecTy); |
| Op = Builder.CreateAnd(Op, Mask); |
| Op = Builder.CreateBitCast(Op, VecTy); |
| return Op; |
| } |
| |
| // Turn FP abs into fabs/fabsf. |
| StringRef Name = SelectFPName(TREE_TYPE(op), "fabsf", "fabs", "fabsl"); |
| if (!Name.empty()) { |
| CallInst *Call = EmitSimpleCall(Name, TREE_TYPE(op), op, NULL); |
| Call->setDoesNotThrow(); |
| Call->setDoesNotAccessMemory(); |
| return Call; |
| } |
| |
| // Otherwise clear the sign bit. |
| Value *Op = EmitRegister(op); |
| Type *Ty = Op->getType(); |
| |
| // Mask = ~(1 << (Bits-1)). |
| unsigned Bits = Ty->getPrimitiveSizeInBits(); |
| Type *IntTy = IntegerType::get(Context, Bits); |
| APInt API = APInt::getAllOnesValue(Bits); |
| API.clearBit(Bits - 1); |
| Constant *Mask = ConstantInt::get(IntTy, API); |
| |
| // Zap the sign bit. |
| Op = Builder.CreateBitCast(Op, IntTy); |
| Op = Builder.CreateAnd(Op, Mask); |
| Op = Builder.CreateBitCast(Op, Ty); |
| return Op; |
| } |
| |
| Value *TreeToLLVM::EmitReg_BIT_NOT_EXPR(tree op) { |
| Value *Op = EmitRegister(op); |
| return Builder.CreateNot(Op, Op->getName() + "not"); |
| } |
| |
| Value *TreeToLLVM::EmitReg_CONJ_EXPR(tree op) { |
| tree elt_type = TREE_TYPE(TREE_TYPE(op)); |
| Value *R, *I; |
| SplitComplex(EmitRegister(op), R, I); |
| |
| // ~(a+ib) = a + i*-b |
| I = CreateAnyNeg(I, elt_type); |
| |
| return CreateComplex(R, I); |
| } |
| |
| Value *TreeToLLVM::EmitReg_CONVERT_EXPR(tree type, tree op) { |
| return EmitRegisterWithCast(op, type); |
| } |
| |
| Value *TreeToLLVM::EmitReg_NEGATE_EXPR(tree op) { |
| Value *V = EmitRegister(op); |
| tree type = TREE_TYPE(op); |
| |
| if (isa<COMPLEX_TYPE>(type)) { |
| tree elt_type = TREE_TYPE(type); |
| Value *R, *I; |
| SplitComplex(V, R, I); |
| |
| // -(a+ib) = -a + i*-b |
| R = CreateAnyNeg(R, elt_type); |
| I = CreateAnyNeg(I, elt_type); |
| |
| return CreateComplex(R, I); |
| } |
| |
| return CreateAnyNeg(V, type); |
| } |
| |
| Value *TreeToLLVM::EmitReg_PAREN_EXPR(tree op) { |
| // TODO: Understand and correctly deal with this subtle expression. |
| return EmitRegister(op); |
| } |
| |
| Value *TreeToLLVM::EmitReg_TRUTH_NOT_EXPR(tree type, tree op) { |
| Value *V = EmitRegister(op); |
| if (!V->getType()->isIntegerTy(1)) |
| V = Builder.CreateICmpNE(V, Constant::getNullValue(V->getType()), |
| "toBool"); |
| V = Builder.CreateNot(V, V->getName() + "not"); |
| return Builder.CreateIntCast(V, getRegType(type), /*isSigned*/ false); |
| } |
| |
| // Comparisons. |
| |
| /// EmitCompare - Compare LHS with RHS using the appropriate comparison code. |
| /// The result is an i1 boolean. |
| Value *TreeToLLVM::EmitCompare(tree lhs, tree rhs, unsigned code) { |
| Value *LHS = EmitRegister(lhs); |
| Value *RHS = TriviallyTypeConvert(EmitRegister(rhs), LHS->getType()); |
| |
| // Compute the LLVM opcodes corresponding to the GCC comparison. |
| CmpInst::Predicate UIPred = CmpInst::BAD_ICMP_PREDICATE; |
| CmpInst::Predicate SIPred = CmpInst::BAD_ICMP_PREDICATE; |
| CmpInst::Predicate FPPred = CmpInst::BAD_FCMP_PREDICATE; |
| |
| switch (code) { |
| default: |
| llvm_unreachable("Unhandled condition code!"); |
| case LT_EXPR: |
| UIPred = CmpInst::ICMP_ULT; |
| SIPred = CmpInst::ICMP_SLT; |
| FPPred = CmpInst::FCMP_OLT; |
| break; |
| case LE_EXPR: |
| UIPred = CmpInst::ICMP_ULE; |
| SIPred = CmpInst::ICMP_SLE; |
| FPPred = CmpInst::FCMP_OLE; |
| break; |
| case GT_EXPR: |
| UIPred = CmpInst::ICMP_UGT; |
| SIPred = CmpInst::ICMP_SGT; |
| FPPred = CmpInst::FCMP_OGT; |
| break; |
| case GE_EXPR: |
| UIPred = CmpInst::ICMP_UGE; |
| SIPred = CmpInst::ICMP_SGE; |
| FPPred = CmpInst::FCMP_OGE; |
| break; |
| case EQ_EXPR: |
| UIPred = SIPred = CmpInst::ICMP_EQ; |
| FPPred = CmpInst::FCMP_OEQ; |
| break; |
| case NE_EXPR: |
| UIPred = SIPred = CmpInst::ICMP_NE; |
| FPPred = CmpInst::FCMP_UNE; |
| break; |
| case UNORDERED_EXPR: |
| FPPred = CmpInst::FCMP_UNO; |
| break; |
| case ORDERED_EXPR: |
| FPPred = CmpInst::FCMP_ORD; |
| break; |
| case UNLT_EXPR: |
| FPPred = CmpInst::FCMP_ULT; |
| break; |
| case UNLE_EXPR: |
| FPPred = CmpInst::FCMP_ULE; |
| break; |
| case UNGT_EXPR: |
| FPPred = CmpInst::FCMP_UGT; |
| break; |
| case UNGE_EXPR: |
| FPPred = CmpInst::FCMP_UGE; |
| break; |
| case UNEQ_EXPR: |
| FPPred = CmpInst::FCMP_UEQ; |
| break; |
| case LTGT_EXPR: |
| FPPred = CmpInst::FCMP_ONE; |
| break; |
| } |
| |
| if (isa<COMPLEX_TYPE>(TREE_TYPE(lhs))) { |
| Value *LHSr, *LHSi; |
| SplitComplex(LHS, LHSr, LHSi); |
| Value *RHSr, *RHSi; |
| SplitComplex(RHS, RHSr, RHSi); |
| |
| Value *DSTr, *DSTi; |
| if (LHSr->getType()->isFloatingPointTy()) { |
| DSTr = Builder.CreateFCmp(FPPred, LHSr, RHSr); |
| DSTi = Builder.CreateFCmp(FPPred, LHSi, RHSi); |
| if (FPPred == CmpInst::FCMP_OEQ) |
| return Builder.CreateAnd(DSTr, DSTi); |
| assert(FPPred == CmpInst::FCMP_UNE && |
| "Unhandled complex comparison!"); |
| return Builder.CreateOr(DSTr, DSTi); |
| } |
| |
| assert(SIPred == UIPred && "(In)equality comparison depends on sign!"); |
| DSTr = Builder.CreateICmp(UIPred, LHSr, RHSr); |
| DSTi = Builder.CreateICmp(UIPred, LHSi, RHSi); |
| if (UIPred == CmpInst::ICMP_EQ) |
| return Builder.CreateAnd(DSTr, DSTi); |
| assert(UIPred == CmpInst::ICMP_NE && "Unhandled complex comparison!"); |
| return Builder.CreateOr(DSTr, DSTi); |
| } |
| |
| if (LHS->getType()->isFPOrFPVectorTy()) |
| return Builder.CreateFCmp(FPPred, LHS, RHS); |
| |
| // Determine which predicate to use based on signedness. |
| CmpInst::Predicate pred = TYPE_UNSIGNED(TREE_TYPE(lhs)) ? UIPred : SIPred; |
| return Builder.CreateICmp(pred, LHS, RHS); |
| } |
| |
| Value *TreeToLLVM::EmitReg_MinMaxExpr(tree op0, tree op1, unsigned UIPred, |
| unsigned SIPred, unsigned FPPred) { |
| Value *LHS = EmitRegister(op0); |
| Value *RHS = EmitRegister(op1); |
| |
| Value *Compare; |
| if (isa<FLOAT_TYPE>(TREE_TYPE(op0))) |
| Compare = Builder.CreateFCmp(FCmpInst::Predicate(FPPred), LHS, RHS); |
| else if (TYPE_UNSIGNED(TREE_TYPE(op0))) |
| Compare = Builder.CreateICmp(ICmpInst::Predicate(UIPred), LHS, RHS); |
| else |
| Compare = Builder.CreateICmp(ICmpInst::Predicate(SIPred), LHS, RHS); |
| |
| return Builder.CreateSelect(Compare, LHS, RHS); |
| } |
| |
| Value *TreeToLLVM::EmitReg_ReducMinMaxExpr( |
| tree op, unsigned UIPred, unsigned SIPred, unsigned FPPred) { |
| // In the bottom half of the vector, form the max/min of the bottom and top |
| // halves of the vector. Rinse and repeat on the just computed bottom half: |
| // in the bottom quarter of the vector, form the max/min of the bottom and |
| // top halves of the bottom half. Continue until only the first element of |
| // the vector is computed. For example, reduc-max <x0, x1, x2, x3> becomes |
| // v = max <x0, x1, undef, undef>, <x2, x3, undef, undef> |
| // w = max <v0, undef, undef, undef>, <v1, undef, undef, undef> |
| // where v = <v0, v1, undef, undef>. The first element of w is the max/min |
| // of x0,x1,x2,x3. |
| Value *Val = EmitRegister(op); |
| Type *Ty = Val->getType(); |
| |
| CmpInst::Predicate Pred = CmpInst::Predicate( |
| isa<FLOAT_TYPE>(TREE_TYPE(op)) ? FPPred : TYPE_UNSIGNED(TREE_TYPE(op)) |
| ? UIPred |
| : SIPred); |
| |
| unsigned Length = (unsigned) TYPE_VECTOR_SUBPARTS(TREE_TYPE(op)); |
| assert(Length > 1 && !(Length & (Length - 1)) && |
| "Length not a power of 2!"); |
| SmallVector<Constant *, 8> Mask(Length); |
| Constant *UndefIndex = UndefValue::get(Type::getInt32Ty(Context)); |
| for (unsigned Elts = Length >> 1; Elts; Elts >>= 1) { |
| // In the extracted vectors, elements with index Elts and on are undefined. |
| for (unsigned i = Elts; i != Length; ++i) |
| Mask[i] = UndefIndex; |
| // Extract elements [0, Elts) from Val. |
| for (unsigned i = 0; i != Elts; ++i) |
| Mask[i] = Builder.getInt32(i); |
| Value *LHS = Builder.CreateShuffleVector(Val, UndefValue::get(Ty), |
| ConstantVector::get(Mask)); |
| // Extract elements [Elts, 2*Elts) from Val. |
| for (unsigned i = 0; i != Elts; ++i) |
| Mask[i] = Builder.getInt32(Elts + i); |
| Value *RHS = Builder.CreateShuffleVector(Val, UndefValue::get(Ty), |
| ConstantVector::get(Mask)); |
| |
| // Replace Val with the max/min of the extracted elements. |
| Value *Compare = |
| isa<FLOAT_TYPE>(TREE_TYPE(op)) ? Builder.CreateFCmp(Pred, LHS, RHS) |
| : Builder.CreateICmp(Pred, LHS, RHS); |
| Val = Builder.CreateSelect(Compare, LHS, RHS); |
| |
| // Repeat, using half as many elements. |
| } |
| |
| return Val; |
| } |
| |
| Value *TreeToLLVM::EmitReg_REDUC_PLUS_EXPR(tree op) { |
| // In the bottom half of the vector, form the sum of the bottom and top halves |
| // of the vector. Rinse and repeat on the just computed bottom half: in the |
| // bottom quarter of the vector, form the sum of the bottom and top halves of |
| // the bottom half. Continue until only the first element of the vector is |
| // computed. For example, reduc-plus <x0, x1, x2, x3> becomes |
| // v = <x0, x1, undef, undef> + <x2, x3, undef, undef> |
| // w = <v0, undef, undef, undef> + <v1, undef, undef, undef> |
| // where v = <v0, v1, undef, undef>. The first element of w is x0+x1+x2+x3. |
| Value *Val = EmitRegister(op); |
| Type *Ty = Val->getType(); |
| |
| unsigned Length = (unsigned) TYPE_VECTOR_SUBPARTS(TREE_TYPE(op)); |
| assert(Length > 1 && !(Length & (Length - 1)) && |
| "Length not a power of 2!"); |
| SmallVector<Constant *, 8> Mask(Length); |
| Constant *UndefIndex = UndefValue::get(Type::getInt32Ty(Context)); |
| for (unsigned Elts = Length >> 1; Elts; Elts >>= 1) { |
| // In the extracted vectors, elements with index Elts and on are undefined. |
| for (unsigned i = Elts; i != Length; ++i) |
| Mask[i] = UndefIndex; |
| // Extract elements [0, Elts) from Val. |
| for (unsigned i = 0; i != Elts; ++i) |
| Mask[i] = Builder.getInt32(i); |
| Value *LHS = Builder.CreateShuffleVector(Val, UndefValue::get(Ty), |
| ConstantVector::get(Mask)); |
| // Extract elements [Elts, 2*Elts) from Val. |
| for (unsigned i = 0; i != Elts; ++i) |
| Mask[i] = Builder.getInt32(Elts + i); |
| Value *RHS = Builder.CreateShuffleVector(Val, UndefValue::get(Ty), |
| ConstantVector::get(Mask)); |
| |
| // Replace Val with the sum of the extracted elements. |
| // TODO: Are nsw/nuw flags valid here? |
| Val = CreateAnyAdd(LHS, RHS, TREE_TYPE(TREE_TYPE(op))); |
| |
| // Repeat, using half as many elements. |
| } |
| |
| return Val; |
| } |
| |
| Value *TreeToLLVM::EmitReg_RotateOp(tree type, tree op0, tree op1, |
| unsigned Opc1, unsigned Opc2) { |
| Value *In = EmitRegister(op0); |
| Value *Amt = EmitRegister(op1); |
| |
| if (Amt->getType() != In->getType()) |
| Amt = Builder.CreateIntCast(Amt, In->getType(), /*isSigned*/ false, |
| Amt->getName() + ".cast"); |
| |
| Value *TypeSize = ConstantInt::get( |
| In->getType(), In->getType()->getPrimitiveSizeInBits()); |
| |
| // Do the two shifts. |
| Value *V1 = Builder.CreateBinOp((Instruction::BinaryOps) Opc1, In, Amt); |
| Value *OtherShift = Builder.CreateSub(TypeSize, Amt); |
| Value *V2 = |
| Builder.CreateBinOp((Instruction::BinaryOps) Opc2, In, OtherShift); |
| |
| // Or the two together to return them. |
| Value *Merge = Builder.CreateOr(V1, V2); |
| return Builder.CreateIntCast(Merge, getRegType(type), /*isSigned*/ false); |
| } |
| |
| Value *TreeToLLVM::EmitReg_ShiftOp(tree op0, tree op1, unsigned Opc) { |
| Value *LHS = EmitRegister(op0); |
| Value *RHS = EmitRegister(op1); |
| // Ensure that the shift amount has the same type as the shiftee. |
| if (RHS->getType() != LHS->getType()) { |
| if (LHS->getType()->isVectorTy() == RHS->getType()->isVectorTy()) { |
| // Scalar shifted by a scalar amount, or a vector shifted by a vector |
| // amount. |
| assert((!LHS->getType()->isVectorTy() || |
| cast<VectorType>(LHS->getType())->getNumElements() == |
| cast<VectorType>(RHS->getType())->getNumElements()) && |
| "Vector length mismatch!"); |
| RHS = CastToAnyType(RHS, /*isSigned*/ false, LHS->getType(), |
| /*isSigned*/ false); |
| } else { |
| // Vector shifted by a scalar amount. Turn the shift amount into a vector |
| // with all elements equal. |
| assert(LHS->getType()->isVectorTy() && |
| "Shifting a scalar by a vector amount!"); |
| VectorType *VecTy = cast<VectorType>(LHS->getType()); |
| RHS = CastToAnyType(RHS, /*isSigned*/ false, VecTy->getElementType(), |
| /*isSigned*/ false); |
| RHS = Builder.CreateInsertElement(UndefValue::get(VecTy), RHS, |
| Builder.getInt32(0)); |
| Type *MaskTy = VectorType::get(Type::getInt32Ty(Context), |
| VecTy->getNumElements()); |
| RHS = Builder.CreateShuffleVector(RHS, UndefValue::get(VecTy), |
| ConstantInt::get(MaskTy, 0)); |
| } |
| } |
| return Builder.CreateBinOp((Instruction::BinaryOps) Opc, LHS, RHS); |
| } |
| |
| Value *TreeToLLVM::EmitReg_VecShiftOp(tree op0, tree op1, |
| bool isLeftShift) { |
| Value *LHS = EmitRegister(op0); // A vector. |
| Value *Amt = EmitRegister(op1); // An integer. |
| VectorType *VecTy = cast<VectorType>(LHS->getType()); |
| unsigned Bits = VecTy->getPrimitiveSizeInBits(); |
| |
| // If the shift is by a multiple of the element size then emit a shuffle. |
| if (ConstantInt *CI = llvm::dyn_cast<ConstantInt>(Amt)) { |
| // The GCC docs are not clear whether the bits shifted in must be zero or if |
| // they can be anything. Since these expressions are currently only used in |
| // situations which make no assumptions about the shifted in bits, we choose |
| // to consider them to be undefined since this results in better code. |
| unsigned ShiftAmt = (unsigned) CI->getLimitedValue(Bits); |
| if (ShiftAmt >= Bits) |
| // Shifting by more than the width of the vector is documented as giving |
| // an undefined result. |
| return UndefValue::get(VecTy); |
| unsigned EltBits = VecTy->getElementType()->getPrimitiveSizeInBits(); |
| if (!(ShiftAmt % EltBits)) { |
| // A shift by an integral number of elements. |
| unsigned EltOffset = |
| ShiftAmt / EltBits; // Shift by this many elements. |
| // Shuffle the elements sideways by the appropriate number of elements. |
| unsigned Length = VecTy->getNumElements(); |
| SmallVector<Constant *, 8> Mask; |
| Mask.reserve(Length); |
| if (isLeftShift) { |
| // shl <4 x i32> %v, 32 -> |
| // shufflevector <4 x i32> %v, <4 x i32> undef, <undef, 0, 1, 2> |
| Mask.append(Length - EltOffset, |
| UndefValue::get(Type::getInt32Ty(Context))); |
| for (unsigned i = 0; i != EltOffset; ++i) |
| Mask.push_back(Builder.getInt32(i)); |
| } else { |
| // shr <4 x i32> %v, 32 -> |
| // shufflevector <4 x i32> %v, <4 x i32> undef, <1, 2, 3, undef> |
| for (unsigned i = EltOffset; i != Length; ++i) |
| Mask.push_back(Builder.getInt32(i)); |
| Mask.append(EltOffset, UndefValue::get(Type::getInt32Ty(Context))); |
| } |
| return Builder.CreateShuffleVector(LHS, UndefValue::get(VecTy), |
| ConstantVector::get(Mask)); |
| } |
| } |
| |
| // Turn the vector into a mighty integer of the same size. |
| LHS = Builder.CreateBitCast(LHS, IntegerType::get(Context, Bits)); |
| |
| // Ensure the shift amount has the same type. |
| if (Amt->getType() != LHS->getType()) |
| Amt = Builder.CreateIntCast(Amt, LHS->getType(), /*isSigned*/ false, |
| Amt->getName() + ".cast"); |
| |
| // Perform the shift. |
| LHS = Builder.CreateBinOp( |
| isLeftShift ? Instruction::Shl : Instruction::LShr, LHS, Amt); |
| |
| // Turn the result back into a vector. |
| return Builder.CreateBitCast(LHS, VecTy); |
| } |
| |
| Value *TreeToLLVM::EmitReg_TruthOp(tree type, tree op0, tree op1, |
| unsigned Opc) { |
| Value *LHS = EmitRegister(op0); |
| Value *RHS = EmitRegister(op1); |
| |
| // This is a truth operation like the strict &&,||,^^. Convert to bool as |
| // a test against zero |
| LHS = Builder.CreateICmpNE(LHS, Constant::getNullValue(LHS->getType()), |
| "toBool"); |
| RHS = Builder.CreateICmpNE(RHS, Constant::getNullValue(RHS->getType()), |
| "toBool"); |
| |
| Value *Res = Builder.CreateBinOp((Instruction::BinaryOps) Opc, LHS, RHS); |
| return Builder.CreateZExt(Res, getRegType(type)); |
| } |
| |
| Value *TreeToLLVM::EmitReg_CEIL_DIV_EXPR(tree op0, tree op1) { |
| // Notation: CEIL_DIV_EXPR <-> CDiv, TRUNC_DIV_EXPR <-> Div. |
| |
| // CDiv calculates LHS/RHS by rounding up to the nearest integer. In terms |
| // of Div this means if the values of LHS and RHS have opposite signs or if |
| // LHS is zero, then CDiv necessarily equals Div; and |
| // LHS CDiv RHS = (LHS - Sign(RHS)) Div RHS + 1 |
| // otherwise. |
| |
| Type *Ty = getRegType(TREE_TYPE(op0)); |
| Constant *Zero = ConstantInt::get(Ty, 0); |
| Constant *One = ConstantInt::get(Ty, 1); |
| Constant *MinusOne = Constant::getAllOnesValue(Ty); |
| |
| Value *LHS = EmitRegister(op0); |
| Value *RHS = EmitRegister(op1); |
| |
| if (!TYPE_UNSIGNED(TREE_TYPE(op0))) { |
| // In the case of signed arithmetic, we calculate CDiv as follows: |
| // LHS CDiv RHS = (LHS - Sign(RHS) * Offset) Div RHS + Offset, |
| // where Offset is 1 if LHS and RHS have the same sign and LHS is |
| // not zero, and 0 otherwise. |
| |
| // On some machines INT_MIN Div -1 traps. You might expect a trap for |
| // INT_MIN CDiv -1 too, but this implementation will not generate one. |
| // Quick quiz question: what value is returned for INT_MIN CDiv -1? |
| |
| // Determine the signs of LHS and RHS, and whether they have the same sign. |
| Value *LHSIsPositive = Builder.CreateICmpSGE(LHS, Zero); |
| Value *RHSIsPositive = Builder.CreateICmpSGE(RHS, Zero); |
| Value *HaveSameSign = |
| Builder.CreateICmpEQ(LHSIsPositive, RHSIsPositive); |
| |
| // Offset equals 1 if LHS and RHS have the same sign and LHS is not zero. |
| Value *LHSNotZero = Builder.CreateICmpNE(LHS, Zero); |
| Value *OffsetOne = Builder.CreateAnd(HaveSameSign, LHSNotZero); |
| // ... otherwise it is 0. |
| Value *Offset = Builder.CreateSelect(OffsetOne, One, Zero); |
| |
| // Calculate Sign(RHS) ... |
| Value *SignRHS = Builder.CreateSelect(RHSIsPositive, One, MinusOne); |
| // ... and Sign(RHS) * Offset |
| Value *SignedOffset = Builder.CreateSExt(OffsetOne, Ty); |
| SignedOffset = Builder.CreateAnd(SignRHS, SignedOffset); |
| |
| // Return CDiv = (LHS - Sign(RHS) * Offset) Div RHS + Offset. |
| Value *CDiv = Builder.CreateSub(LHS, SignedOffset); |
| CDiv = Builder.CreateSDiv(CDiv, RHS); |
| return Builder.CreateAdd(CDiv, Offset, "cdiv"); |
| } |
| |
| // In the case of unsigned arithmetic, LHS and RHS necessarily have the |
| // same sign, so we can use |
| // LHS CDiv RHS = (LHS - 1) Div RHS + 1 |
| // as long as LHS is non-zero. |
| |
| // Offset is 1 if LHS is non-zero, 0 otherwise. |
| Value *LHSNotZero = Builder.CreateICmpNE(LHS, Zero); |
| Value *Offset = Builder.CreateSelect(LHSNotZero, One, Zero); |
| |
| // Return CDiv = (LHS - Offset) Div RHS + Offset. |
| Value *CDiv = Builder.CreateSub(LHS, Offset); |
| CDiv = Builder.CreateUDiv(CDiv, RHS); |
| return Builder.CreateAdd(CDiv, Offset, "cdiv"); |
| } |
| |
| Value *TreeToLLVM::EmitReg_BIT_AND_EXPR(tree op0, tree op1) { |
| Value *LHS = CastToSameSizeInteger(EmitRegister(op0)); |
| Value *RHS = CastToSameSizeInteger(EmitRegister(op1)); |
| Value *Res = Builder.CreateAnd(LHS, RHS); |
| return CastFromSameSizeInteger(Res, getRegType(TREE_TYPE(op0))); |
| } |
| |
| Value *TreeToLLVM::EmitReg_BIT_IOR_EXPR(tree op0, tree op1) { |
| Value *LHS = CastToSameSizeInteger(EmitRegister(op0)); |
| Value *RHS = CastToSameSizeInteger(EmitRegister(op1)); |
| Value *Res = Builder.CreateOr(LHS, RHS); |
| return CastFromSameSizeInteger(Res, getRegType(TREE_TYPE(op0))); |
| } |
| |
| Value *TreeToLLVM::EmitReg_BIT_XOR_EXPR(tree op0, tree op1) { |
| Value *LHS = CastToSameSizeInteger(EmitRegister(op0)); |
| Value *RHS = CastToSameSizeInteger(EmitRegister(op1)); |
| Value *Res = Builder.CreateXor(LHS, RHS); |
| return CastFromSameSizeInteger(Res, getRegType(TREE_TYPE(op0))); |
| } |
| |
| /// EmitReg_CondExpr - Handle COND_EXPR and VEC_COND_EXPR gimple assign right- |
| /// hand sides. |
| Value *TreeToLLVM::EmitReg_CondExpr(tree op0, tree op1, tree op2) { |
| // The condition is either a comparison or an SSA register. Note that the |
| // reason for accessing tree operands directly rather than taking advantage |
| // of COND_EXPR_COND and friends is that the latter fail for VEC_COND_EXPR, |
| // which is also handled here. |
| Value *CondVal = COMPARISON_CLASS_P(op0) |
| ? EmitCompare(TREE_OPERAND(op0, 0), TREE_OPERAND(op0, 1), |
| TREE_CODE(op0)) |
| : EmitRegister(op0); |
| |
| // Ensure the condition has i1 type. |
| if (!CondVal->getType()->getScalarType()->isIntegerTy(1)) |
| CondVal = Builder.CreateICmpNE( |
| CondVal, Constant::getNullValue(CondVal->getType())); |
| |
| // Emit the true and false values. |
| Value *TrueVal = EmitRegister(op1); |
| Value *FalseVal = EmitRegister(op2); |
| FalseVal = TriviallyTypeConvert(FalseVal, TrueVal->getType()); |
| |
| // Select the value to use based on the condition. |
| return Builder.CreateSelect(CondVal, TrueVal, FalseVal); |
| } |
| |
| Value *TreeToLLVM::EmitReg_COMPLEX_EXPR(tree op0, tree op1) { |
| return CreateComplex(EmitRegister(op0), EmitRegister(op1)); |
| } |
| |
| Value *TreeToLLVM::EmitReg_FLOOR_DIV_EXPR(tree op0, tree op1) { |
| // Notation: FLOOR_DIV_EXPR <-> FDiv, TRUNC_DIV_EXPR <-> Div. |
| Value *LHS = EmitRegister(op0); |
| Value *RHS = EmitRegister(op1); |
| |
| // FDiv calculates LHS/RHS by rounding down to the nearest integer. In terms |
| // of Div this means if the values of LHS and RHS have the same sign or if LHS |
| // is zero, then FDiv necessarily equals Div; and |
| // LHS FDiv RHS = (LHS + Sign(RHS)) Div RHS - 1 |
| // otherwise. |
| |
| if (TYPE_UNSIGNED(TREE_TYPE(op0))) |
| // In the case of unsigned arithmetic, LHS and RHS necessarily have the |
| // same sign, so FDiv is the same as Div. |
| return Builder.CreateUDiv(LHS, RHS, "fdiv"); |
| |
| Type *Ty = getRegType(TREE_TYPE(op0)); |
| Constant *Zero = ConstantInt::get(Ty, 0); |
| Constant *One = ConstantInt::get(Ty, 1); |
| Constant *MinusOne = Constant::getAllOnesValue(Ty); |
| |
| // In the case of signed arithmetic, we calculate FDiv as follows: |
| // LHS FDiv RHS = (LHS + Sign(RHS) * Offset) Div RHS - Offset, |
| // where Offset is 1 if LHS and RHS have opposite signs and LHS is |
| // not zero, and 0 otherwise. |
| |
| // Determine the signs of LHS and RHS, and whether they have the same sign. |
| Value *LHSIsPositive = Builder.CreateICmpSGE(LHS, Zero); |
| Value *RHSIsPositive = Builder.CreateICmpSGE(RHS, Zero); |
| Value *SignsDiffer = Builder.CreateICmpNE(LHSIsPositive, RHSIsPositive); |
| |
| // Offset equals 1 if LHS and RHS have opposite signs and LHS is not zero. |
| Value *LHSNotZero = Builder.CreateICmpNE(LHS, Zero); |
| Value *OffsetOne = Builder.CreateAnd(SignsDiffer, LHSNotZero); |
| // ... otherwise it is 0. |
| Value *Offset = Builder.CreateSelect(OffsetOne, One, Zero); |
| |
| // Calculate Sign(RHS) ... |
| Value *SignRHS = Builder.CreateSelect(RHSIsPositive, One, MinusOne); |
| // ... and Sign(RHS) * Offset |
| Value *SignedOffset = Builder.CreateSExt(OffsetOne, Ty); |
| SignedOffset = Builder.CreateAnd(SignRHS, SignedOffset); |
| |
| // Return FDiv = (LHS + Sign(RHS) * Offset) Div RHS - Offset. |
| Value *FDiv = Builder.CreateAdd(LHS, SignedOffset); |
| FDiv = Builder.CreateSDiv(FDiv, RHS); |
| return Builder.CreateSub(FDiv, Offset, "fdiv"); |
| } |
| |
| Value *TreeToLLVM::EmitReg_FLOOR_MOD_EXPR(tree op0, tree op1) { |
| // Notation: FLOOR_MOD_EXPR <-> Mod, TRUNC_MOD_EXPR <-> Rem. |
| |
| Value *LHS = EmitRegister(op0); |
| Value *RHS = EmitRegister(op1); |
| |
| // We express Mod in terms of Rem as follows: if RHS exactly divides LHS, |
| // or the values of LHS and RHS have the same sign, then Mod equals Rem. |
| // Otherwise Mod equals Rem + RHS. This means that LHS Mod RHS traps iff |
| // LHS Rem RHS traps. |
| if (TYPE_UNSIGNED(TREE_TYPE(op0))) |
| // LHS and RHS values must have the same sign if their type is unsigned. |
| return Builder.CreateURem(LHS, RHS); |
| |
| Type *Ty = getRegType(TREE_TYPE(op0)); |
| Constant *Zero = ConstantInt::get(Ty, 0); |
| |
| // The two possible values for Mod. |
| Value *Rem = Builder.CreateSRem(LHS, RHS, "rem"); |
| Value *RemPlusRHS = Builder.CreateAdd(Rem, RHS); |
| |
| // HaveSameSign: (LHS >= 0) == (RHS >= 0). |
| Value *LHSIsPositive = Builder.CreateICmpSGE(LHS, Zero); |
| Value *RHSIsPositive = Builder.CreateICmpSGE(RHS, Zero); |
| Value *HaveSameSign = Builder.CreateICmpEQ(LHSIsPositive, RHSIsPositive); |
| |
| // RHS exactly divides LHS iff Rem is zero. |
| Value *RemIsZero = Builder.CreateICmpEQ(Rem, Zero); |
| |
| Value *SameAsRem = Builder.CreateOr(HaveSameSign, RemIsZero); |
| return Builder.CreateSelect(SameAsRem, Rem, RemPlusRHS, "mod"); |
| } |
| |
| Value *TreeToLLVM::EmitReg_MINUS_EXPR(tree op0, tree op1) { |
| Value *LHS = EmitRegister(op0); |
| Value *RHS = EmitRegister(op1); |
| tree type = TREE_TYPE(op0); |
| |
| if (isa<COMPLEX_TYPE>(type)) { |
| tree elt_type = TREE_TYPE(type); |
| Value *LHSr, *LHSi; |
| SplitComplex(LHS, LHSr, LHSi); |
| Value *RHSr, *RHSi; |
| SplitComplex(RHS, RHSr, RHSi); |
| |
| // (a+ib) - (c+id) = (a-c) + i(b-d) |
| LHSr = CreateAnySub(LHSr, RHSr, elt_type); |
| LHSi = CreateAnySub(LHSi, RHSi, elt_type); |
| |
| return CreateComplex(LHSr, LHSi); |
| } |
| |
| return CreateAnySub(LHS, RHS, type); |
| } |
| |
| Value *TreeToLLVM::EmitReg_MULT_EXPR(tree op0, tree op1) { |
| Value *LHS = EmitRegister(op0); |
| Value *RHS = EmitRegister(op1); |
| tree type = TREE_TYPE(op0); |
| |
| if (isa<COMPLEX_TYPE>(type)) { |
| tree elt_type = TREE_TYPE(type); |
| Value *LHSr, *LHSi; |
| SplitComplex(LHS, LHSr, LHSi); |
| Value *RHSr, *RHSi; |
| SplitComplex(RHS, RHSr, RHSi); |
| Value *DSTr, *DSTi; |
| |
| // (a+ib) * (c+id) = (ac-bd) + i(ad+cb) |
| if (isa<REAL_TYPE>(elt_type)) { |
| Value *Tmp1 = Builder.CreateFMul(LHSr, RHSr); // a*c |
| Value *Tmp2 = Builder.CreateFMul(LHSi, RHSi); // b*d |
| DSTr = Builder.CreateFSub(Tmp1, Tmp2); // ac-bd |
| |
| Value *Tmp3 = Builder.CreateFMul(LHSr, RHSi); // a*d |
| Value *Tmp4 = Builder.CreateFMul(RHSr, LHSi); // c*b |
| DSTi = Builder.CreateFAdd(Tmp3, Tmp4); // ad+cb |
| } else { |
| // If overflow does not wrap in the element type then it is tempting to |
| // use NSW operations here. However that would be wrong since overflow |
| // of an intermediate value calculated here does not necessarily imply |
| // that the final result overflows. |
| Value *Tmp1 = Builder.CreateMul(LHSr, RHSr); // a*c |
| Value *Tmp2 = Builder.CreateMul(LHSi, RHSi); // b*d |
| DSTr = Builder.CreateSub(Tmp1, Tmp2); // ac-bd |
| |
| Value *Tmp3 = Builder.CreateMul(LHSr, RHSi); // a*d |
| Value *Tmp4 = Builder.CreateMul(RHSr, LHSi); // c*b |
| DSTi = Builder.CreateAdd(Tmp3, Tmp4); // ad+cb |
| } |
| |
| return CreateComplex(DSTr, DSTi); |
| } |
| |
| return CreateAnyMul(LHS, RHS, type); |
| } |
| |
| Value *TreeToLLVM::EmitReg_PLUS_EXPR(tree op0, tree op1) { |
| Value *LHS = EmitRegister(op0); |
| Value *RHS = EmitRegister(op1); |
| tree type = TREE_TYPE(op0); |
| |
| if (isa<COMPLEX_TYPE>(type)) { |
| tree elt_type = TREE_TYPE(type); |
| Value *LHSr, *LHSi; |
| SplitComplex(LHS, LHSr, LHSi); |
| Value *RHSr, *RHSi; |
| SplitComplex(RHS, RHSr, RHSi); |
| |
| // (a+ib) + (c+id) = (a+c) + i(b+d) |
| LHSr = CreateAnyAdd(LHSr, RHSr, elt_type); |
| LHSi = CreateAnyAdd(LHSi, RHSi, elt_type); |
| |
| return CreateComplex(LHSr, LHSi); |
| } |
| |
| return CreateAnyAdd(LHS, RHS, type); |
| } |
| |
| Value *TreeToLLVM::EmitReg_POINTER_PLUS_EXPR(tree op0, tree op1) { |
| Value *Ptr = EmitRegister(op0); // The pointer. |
| Value *Idx = EmitRegister(op1); // The offset in units. |
| |
| // Convert the pointer into an i8* and add the offset to it. |
| Ptr = Builder.CreateBitCast(Ptr, GetUnitPointerType(Context)); |
| StringRef GEPName = flag_verbose_asm ? "pp" : ""; |
| return POINTER_TYPE_OVERFLOW_UNDEFINED |
| ? Builder.CreateInBoundsGEP(Ptr, Idx, GEPName) |
| : Builder.CreateGEP(Ptr, Idx, GEPName); |
| } |
| |
| Value *TreeToLLVM::EmitReg_RDIV_EXPR(tree op0, tree op1) { |
| Value *LHS = EmitRegister(op0); |
| Value *RHS = EmitRegister(op1); |
| tree type = TREE_TYPE(op0); |
| |
| if (isa<COMPLEX_TYPE>(type)) { |
| Value *LHSr, *LHSi; |
| SplitComplex(LHS, LHSr, LHSi); |
| Value *RHSr, *RHSi; |
| SplitComplex(RHS, RHSr, RHSi); |
| Value *DSTr, *DSTi; |
| |
| // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) |
| assert(isa<REAL_TYPE>(TREE_TYPE(type)) && |
| "RDIV_EXPR not floating point!"); |
| Value *Tmp1 = Builder.CreateFMul(LHSr, RHSr); // a*c |
| Value *Tmp2 = Builder.CreateFMul(LHSi, RHSi); // b*d |
| Value *Tmp3 = Builder.CreateFAdd(Tmp1, Tmp2); // ac+bd |
| |
| Value *Tmp4 = Builder.CreateFMul(RHSr, RHSr); // c*c |
| Value *Tmp5 = Builder.CreateFMul(RHSi, RHSi); // d*d |
| Value *Tmp6 = Builder.CreateFAdd(Tmp4, Tmp5); // cc+dd |
| DSTr = Builder.CreateFDiv(Tmp3, Tmp6); |
| |
| Value *Tmp7 = Builder.CreateFMul(LHSi, RHSr); // b*c |
| Value *Tmp8 = Builder.CreateFMul(LHSr, RHSi); // a*d |
| Value *Tmp9 = Builder.CreateFSub(Tmp7, Tmp8); // bc-ad |
| DSTi = Builder.CreateFDiv(Tmp9, Tmp6); |
| |
| return CreateComplex(DSTr, DSTi); |
| } |
| |
| assert(isa<FLOAT_TYPE>(type) && "RDIV_EXPR not floating point!"); |
| return Builder.CreateFDiv(LHS, RHS); |
| } |
| |
| Value *TreeToLLVM::EmitReg_ROUND_DIV_EXPR(tree op0, tree op1) { |
| // Notation: ROUND_DIV_EXPR <-> RDiv, TRUNC_DIV_EXPR <-> Div. |
| |
| // RDiv calculates LHS/RHS by rounding to the nearest integer. Ties |
| // are broken by rounding away from zero. In terms of Div this means: |
| // LHS RDiv RHS = (LHS + (RHS Div 2)) Div RHS |
| // if the values of LHS and RHS have the same sign; and |
| // LHS RDiv RHS = (LHS - (RHS Div 2)) Div RHS |
| // if the values of LHS and RHS differ in sign. The intermediate |
| // expressions in these formulae can overflow, so some tweaking is |
| // required to ensure correct results. The details depend on whether |
| // we are doing signed or unsigned arithmetic. |
| |
| Type *Ty = getRegType(TREE_TYPE(op0)); |
| Constant *Zero = ConstantInt::get(Ty, 0); |
| Constant *Two = ConstantInt::get(Ty, 2); |
| |
| Value *LHS = EmitRegister(op0); |
| Value *RHS = EmitRegister(op1); |
| |
| if (!TYPE_UNSIGNED(TREE_TYPE(op0))) { |
| // In the case of signed arithmetic, we calculate RDiv as follows: |
| // LHS RDiv RHS = (sign) ( (|LHS| + (|RHS| UDiv 2)) UDiv |RHS| ), |
| // where sign is +1 if LHS and RHS have the same sign, -1 if their |
| // signs differ. Doing the computation unsigned ensures that there |
| // is no overflow. |
| |
| // On some machines INT_MIN Div -1 traps. You might expect a trap for |
| // INT_MIN RDiv -1 too, but this implementation will not generate one. |
| // Quick quiz question: what value is returned for INT_MIN RDiv -1? |
| |
| // Determine the signs of LHS and RHS, and whether they have the same sign. |
| Value *LHSIsPositive = Builder.CreateICmpSGE(LHS, Zero); |
| Value *RHSIsPositive = Builder.CreateICmpSGE(RHS, Zero); |
| Value *HaveSameSign = |
| Builder.CreateICmpEQ(LHSIsPositive, RHSIsPositive); |
| |
| // Calculate |LHS| ... |
| Value *MinusLHS = Builder.CreateNeg(LHS); |
| Value *AbsLHS = Builder.CreateSelect(LHSIsPositive, LHS, MinusLHS, |
| LHS->getName() + ".abs"); |
| // ... and |RHS| |
| Value *MinusRHS = Builder.CreateNeg(RHS); |
| Value *AbsRHS = Builder.CreateSelect(RHSIsPositive, RHS, MinusRHS, |
| RHS->getName() + ".abs"); |
| |
| // Calculate AbsRDiv = (|LHS| + (|RHS| UDiv 2)) UDiv |RHS|. |
| Value *HalfAbsRHS = Builder.CreateUDiv(AbsRHS, Two); |
| Value *Numerator = Builder.CreateAdd(AbsLHS, HalfAbsRHS); |
| Value *AbsRDiv = Builder.CreateUDiv(Numerator, AbsRHS); |
| |
| // Return AbsRDiv or -AbsRDiv according to whether LHS and RHS have the |
| // same sign or not. |
| Value *MinusAbsRDiv = Builder.CreateNeg(AbsRDiv); |
| return Builder.CreateSelect(HaveSameSign, AbsRDiv, MinusAbsRDiv, |
| "rdiv"); |
| } |
| |
| // In the case of unsigned arithmetic, LHS and RHS necessarily have the |
| // same sign, however overflow is a problem. We want to use the formula |
| // LHS RDiv RHS = (LHS + (RHS Div 2)) Div RHS, |
| // but if LHS + (RHS Div 2) overflows then we get the wrong result. Since |
| // the use of a conditional branch seems to be unavoidable, we choose the |
| // simple solution of explicitly checking for overflow, and using |
| // LHS RDiv RHS = ((LHS + (RHS Div 2)) - RHS) Div RHS + 1 |
| // if it occurred. |
| |
| // Usually the numerator is LHS + (RHS Div 2); calculate this. |
| Value *HalfRHS = Builder.CreateUDiv(RHS, Two); |
| Value *Numerator = Builder.CreateAdd(LHS, HalfRHS); |
| |
| // Did the calculation overflow? |
| Value *Overflowed = Builder.CreateICmpULT(Numerator, HalfRHS); |
| |
| // If so, use (LHS + (RHS Div 2)) - RHS for the numerator instead. |
| Value *AltNumerator = Builder.CreateSub(Numerator, RHS); |
| Numerator = Builder.CreateSelect(Overflowed, AltNumerator, Numerator); |
| |
| // Quotient = Numerator / RHS. |
| Value *Quotient = Builder.CreateUDiv(Numerator, RHS); |
| |
| // Return Quotient unless we overflowed, in which case return Quotient + 1. |
| return Builder.CreateAdd( |
| Quotient, Builder.CreateIntCast(Overflowed, Ty, /*isSigned*/ false), |
| "rdiv"); |
| } |
| |
| Value *TreeToLLVM::EmitReg_TRUNC_DIV_EXPR(tree op0, tree op1, |
| bool isExact) { |
| Value *LHS = EmitRegister(op0); |
| Value *RHS = EmitRegister(op1); |
| tree type = TREE_TYPE(op0); |
| |
| if (isa<COMPLEX_TYPE>(type)) { |
| tree elt_type = TREE_TYPE(type); |
| Value *LHSr, *LHSi; |
| SplitComplex(LHS, LHSr, LHSi); |
| Value *RHSr, *RHSi; |
| SplitComplex(RHS, RHSr, RHSi); |
| Value *DSTr, *DSTi; |
| |
| // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) |
| assert(LHSr->getType()->isIntegerTy() && "TRUNC_DIV_EXPR not integer!"); |
| // If overflow does not wrap in the element type then it is tempting to |
| // use NSW operations here. However that would be wrong since overflow |
| // of an intermediate value calculated here does not necessarily imply |
| // that the final result overflows. |
| Value *Tmp1 = Builder.CreateMul(LHSr, RHSr); // a*c |
| Value *Tmp2 = Builder.CreateMul(LHSi, RHSi); // b*d |
| Value *Tmp3 = Builder.CreateAdd(Tmp1, Tmp2); // ac+bd |
| |
| Value *Tmp4 = Builder.CreateMul(RHSr, RHSr); // c*c |
| Value *Tmp5 = Builder.CreateMul(RHSi, RHSi); // d*d |
| Value *Tmp6 = Builder.CreateAdd(Tmp4, Tmp5); // cc+dd |
| DSTr = TYPE_UNSIGNED(elt_type) ? Builder.CreateUDiv(Tmp3, Tmp6) |
| : Builder.CreateSDiv(Tmp3, Tmp6); |
| |
| Value *Tmp7 = Builder.CreateMul(LHSi, RHSr); // b*c |
| Value *Tmp8 = Builder.CreateMul(LHSr, RHSi); // a*d |
| Value *Tmp9 = Builder.CreateSub(Tmp7, Tmp8); // bc-ad |
| DSTi = TYPE_UNSIGNED(elt_type) ? Builder.CreateUDiv(Tmp9, Tmp6) |
| : Builder.CreateSDiv(Tmp9, Tmp6); |
| |
| return CreateComplex(DSTr, DSTi); |
| } |
| |
| assert(LHS->getType()->isIntOrIntVectorTy() && |
| "TRUNC_DIV_EXPR not integer!"); |
| if (TYPE_UNSIGNED(type)) |
| return Builder.CreateUDiv(LHS, RHS, "", isExact); |
| else |
| return Builder.CreateSDiv(LHS, RHS, "", isExact); |
| } |
| |
| Value *TreeToLLVM::EmitReg_TRUNC_MOD_EXPR(tree op0, tree op1) { |
| Value *LHS = EmitRegister(op0); |
| Value *RHS = EmitRegister(op1); |
| return TYPE_UNSIGNED(TREE_TYPE(op0)) ? Builder.CreateURem(LHS, RHS) |
| : Builder.CreateSRem(LHS, RHS); |
| } |
| |
| #if (GCC_MINOR < 7) |
| Value *TreeToLLVM::EmitReg_VEC_EXTRACT_EVEN_EXPR(tree op0, tree op1) { |
| Value *LHS = EmitRegister(op0); |
| Value *RHS = EmitRegister(op1); |
| unsigned Length = (unsigned) TYPE_VECTOR_SUBPARTS(TREE_TYPE(op0)); |
| SmallVector<Constant *, 16> Mask; |
| Mask.reserve(Length); |
| for (unsigned i = 0; i != Length; ++i) |
| Mask.push_back(Builder.getInt32(2 * i)); |
| return Builder.CreateShuffleVector(LHS, RHS, ConstantVector::get(Mask)); |
| } |
| #endif |
| |
| #if (GCC_MINOR < 7) |
| Value *TreeToLLVM::EmitReg_VEC_EXTRACT_ODD_EXPR(tree op0, tree op1) { |
| Value *LHS = EmitRegister(op0); |
| Value *RHS = EmitRegister(op1); |
| unsigned Length = (unsigned) TYPE_VECTOR_SUBPARTS(TREE_TYPE(op0)); |
| SmallVector<Constant *, 16> Mask; |
| Mask.reserve(Length); |
| for (unsigned i = 0; i != Length; ++i) |
| Mask.push_back(Builder.getInt32(2 * i + 1)); |
| return Builder.CreateShuffleVector(LHS, RHS, ConstantVector::get(Mask)); |
| } |
| #endif |
| |
| #if (GCC_MINOR < 7) |
| Value *TreeToLLVM::EmitReg_VEC_INTERLEAVE_HIGH_EXPR(tree op0, tree op1) { |
| Value *LHS = EmitRegister(op0); |
| Value *RHS = EmitRegister(op1); |
| unsigned Length = (unsigned) TYPE_VECTOR_SUBPARTS(TREE_TYPE(op0)); |
| assert(!(Length & 1) && "Expected an even number of vector elements!"); |
| SmallVector<Constant *, 16> Mask; |
| Mask.reserve(Length); |
| for (unsigned i = Length / 2; i != Length; ++i) { |
| Mask.push_back(Builder.getInt32(i)); |
| Mask.push_back(Builder.getInt32(Length + i)); |
| } |
| return Builder.CreateShuffleVector(LHS, RHS, ConstantVector::get(Mask)); |
| } |
| #endif |
| |
| #if (GCC_MINOR < 7) |
| Value *TreeToLLVM::EmitReg_VEC_INTERLEAVE_LOW_EXPR(tree op0, tree op1) { |
| Value *LHS = EmitRegister(op0); |
| Value *RHS = EmitRegister(op1); |
| unsigned Length = (unsigned) TYPE_VECTOR_SUBPARTS(TREE_TYPE(op0)); |
| assert(!(Length & 1) && "Expected an even number of vector elements!"); |
| SmallVector<Constant *, 16> Mask; |
| Mask.reserve(Length); |
| for (unsigned i = 0, e = Length / 2; i != e; ++i) { |
| Mask.push_back(Builder.getInt32(i)); |
| Mask.push_back(Builder.getInt32(Length + i)); |
| } |
| return Builder.CreateShuffleVector(LHS, RHS, ConstantVector::get(Mask)); |
| } |
| #endif |
| |
| Value *TreeToLLVM::EmitReg_VEC_PACK_TRUNC_EXPR(tree type, tree op0, |
| tree op1) { |
| // Eg: <4 x float> = VEC_PACK_TRUNC_EXPR(<2 x double>, <2 x double>) |
| // or <4 x i32> = VEC_PACK_FIX_TRUNC_EXPR(<2 x double>, <2 x double>). |
| Value *LHS = EmitRegister(op0); |
| Value *RHS = EmitRegister(op1); |
| |
| // Truncate the input elements to the output element type, eg: <2 x double> |
| // -> <2 x float>. |
| unsigned Length = (unsigned) TYPE_VECTOR_SUBPARTS(TREE_TYPE(op0)); |
| Type *DestTy = VectorType::get(getRegType(TREE_TYPE(type)), Length); |
| LHS = CastToAnyType(LHS, !TYPE_UNSIGNED(TREE_TYPE(TREE_TYPE(op0))), |
| DestTy, !TYPE_UNSIGNED(TREE_TYPE(type))); |
| RHS = CastToAnyType(RHS, !TYPE_UNSIGNED(TREE_TYPE(TREE_TYPE(op0))), |
| DestTy, !TYPE_UNSIGNED(TREE_TYPE(type))); |
| |
| // Concatenate the truncated inputs into one vector of twice the length, |
| // eg: <2 x float>, <2 x float> -> <4 x float>. |
| SmallVector<Constant *, 16> Mask; |
| Mask.reserve(2 * Length); |
| for (unsigned i = 0, e = 2 * Length; i != e; ++i) |
| Mask.push_back(Builder.getInt32(i)); |
| return Builder.CreateShuffleVector(LHS, RHS, ConstantVector::get(Mask)); |
| } |
| |
| #if (GCC_MINOR > 6) |
| Value *TreeToLLVM::EmitReg_VEC_PERM_EXPR(tree op0, tree op1, tree op2) { |
| unsigned Length = (unsigned) TYPE_VECTOR_SUBPARTS(TREE_TYPE(op0)); |
| |
| // The vectors to shuffle. |
| Value *V0 = EmitRegister(op0); |
| Value *V1 = EmitRegister(op1); |
| |
| // The shuffle mask. |
| Value *Mask = EmitRegister(op2); |
| |
| // The GCC semantics are that mask indices off the end are wrapped back into |
| // range, so reduce the mask modulo 2*Length. |
| assert(!(Length & (Length - 1)) && "Vector length not a power of two!"); |
| Mask = Builder.CreateAnd( |
| Mask, ConstantInt::get(Mask->getType(), 2 * Length - 1)); |
| |
| // Convert to a vector of i32, as required by the shufflevector instruction. |
| Type *MaskTy = VectorType::get(Builder.getInt32Ty(), Length); |
| tree mask_elt_type = TREE_TYPE(TREE_TYPE(op2)); |
| Value *Mask32 = |
| Builder.CreateIntCast(Mask, MaskTy, !TYPE_UNSIGNED(mask_elt_type)); |
| |
| // Use a shufflevector instruction if this directly corresponds to one, i.e. |
| // if the mask is a vector of constant integers or undef. |
| if (ShuffleVectorInst::isValidOperands(V0, V1, Mask32)) |
| return Builder.CreateShuffleVector(V0, V1, Mask32); |
| |
| // Store the vectors to successive memory locations in a temporary. |
| tree elt_type = TREE_TYPE(TREE_TYPE(op0)); |
| Type *EltTy = ConvertType(elt_type); |
| unsigned Align = DL.getABITypeAlignment(EltTy); |
| // The temporary is a struct containing the pair of input vectors. |
| Type *TmpTy = StructType::get(ConvertType(TREE_TYPE(op0)), |
| ConvertType(TREE_TYPE(op1)), NULL); |
| AllocaInst *Tmp = CreateTemporary(TmpTy, Align); |
| // Store the first vector to the first element of the pair. |
| Value *Tmp0 = |
| Builder.CreateStructGEP(Tmp, 0, flag_verbose_asm ? "vp1s" : ""); |
| StoreRegisterToMemory(V0, MemRef(Tmp0, Align, /*Volatile*/ false), |
| TREE_TYPE(op0), 0, Builder); |
| // Store the second vector to the second element of the pair. |
| Value *Tmp1 = |
| Builder.CreateStructGEP(Tmp, 1, flag_verbose_asm ? "vp2s" : ""); |
| StoreRegisterToMemory(V1, MemRef(Tmp1, Align, /*Volatile*/ false), |
| TREE_TYPE(op1), 0, Builder); |
| |
| // Load out the components according to the mask. |
| Value *Result = UndefValue::get(V0->getType()); |
| Value *BaseAddr = Builder.CreateBitCast(Tmp, EltTy->getPointerTo()); |
| for (unsigned i = 0; i != Length; ++i) { |
| // Extract from the mask the index of the element to load. |
| Value *MaskIdx = Builder.getInt32(i); |
| Value *Idx = Builder.CreateExtractElement(Mask, MaskIdx); |
| // Advance that many elements from the start of the temporary and load it. |
| Value *Ptr = Builder.CreateInBoundsGEP(BaseAddr, Idx, |
| flag_verbose_asm ? "vpl" : ""); |
| Value *Elt = LoadRegisterFromMemory(MemRef(Ptr, Align, false), elt_type, |
| 0, Builder); |
| // Insert it into the result. |
| Result = Builder.CreateInsertElement(Result, Elt, MaskIdx); |
| } |
| return Result; |
| } |
| #endif |
| |
| Value *TreeToLLVM::EmitReg_VecUnpackHiExpr(tree type, tree op0) { |
| // Eg: <2 x double> = VEC_UNPACK_HI_EXPR(<4 x float>) |
| Value *Op = EmitRegister(op0); |
| |
| // Extract the high elements, eg: <4 x float> -> <2 x float>. |
| Op = VectorHighElements(Op); |
| |
| // Extend the input elements to the output element type, eg: <2 x float> |
| // -> <2 x double>. |
| Type *DestTy = getRegType(type); |
| return CastToAnyType(Op, !TYPE_UNSIGNED(TREE_TYPE(TREE_TYPE(op0))), |
| DestTy, !TYPE_UNSIGNED(TREE_TYPE(type))); |
| } |
| |
| Value *TreeToLLVM::EmitReg_VecUnpackLoExpr(tree type, tree op0) { |
| // Eg: <2 x double> = VEC_UNPACK_LO_EXPR(<4 x float>) |
| Value *Op = EmitRegister(op0); |
| |
| // Extract the low elements, eg: <4 x float> -> <2 x float>. |
| Op = VectorLowElements(Op); |
| |
| // Extend the input elements to the output element type, eg: <2 x float> |
| // -> <2 x double>. |
| Type *DestTy = getRegType(type); |
| return CastToAnyType(Op, !TYPE_UNSIGNED(TREE_TYPE(TREE_TYPE(op0))), |
| DestTy, !TYPE_UNSIGNED(TREE_TYPE(type))); |
| } |
| |
| Value *TreeToLLVM::EmitReg_VEC_WIDEN_MULT_HI_EXPR(tree type, tree op0, |
| tree op1) { |
| Value *Hi0 = EmitReg_VecUnpackHiExpr(type, op0); |
| Value *Hi1 = EmitReg_VecUnpackHiExpr(type, op1); |
| return Builder.CreateMul(Hi0, Hi1); |
| } |
| |
| Value *TreeToLLVM::EmitReg_VEC_WIDEN_MULT_LO_EXPR(tree type, tree op0, |
| tree op1) { |
| Value *Lo0 = EmitReg_VecUnpackLoExpr(type, op0); |
| Value *Lo1 = EmitReg_VecUnpackLoExpr(type, op1); |
| return Builder.CreateMul(Lo0, Lo1); |
| } |
| |
| Value *TreeToLLVM::EmitReg_WIDEN_MULT_EXPR(tree type, tree op0, tree op1) { |
| Value *LHS = EmitRegisterWithCast(op0, type); |
| Value *RHS = EmitRegisterWithCast(op1, type); |
| return Builder.CreateMul(LHS, RHS); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // ... Exception Handling ... |
| //===----------------------------------------------------------------------===// |
| |
| //===----------------------------------------------------------------------===// |
| // ... Render* - Convert GIMPLE to LLVM ... |
| //===----------------------------------------------------------------------===// |
| |
| void TreeToLLVM::RenderGIMPLE_ASM(gimple stmt) { |
| // A gimple asm statement consists of an asm string, a list of outputs, a list |
| // of inputs, a list of clobbers, a list of labels and a "volatile" flag. |
| // These correspond directly to the elements of an asm statement. For example |
| // asm ("combine %2,%0" : "=r" (x) : "0" (x), "g" (y)); |
| // Here the asm string is "combine %2,%0" and can be obtained as a const char* |
| // by calling gimple_asm_string. The only output is "=r" (x). The number of |
| // outputs is given by gimple_asm_noutputs, 1 in this case, and the outputs |
| // themselves can be obtained by calling gimple_asm_output_op. This returns a |
| // TREE_LIST node with an SSA name for "x" as the TREE_VALUE; the TREE_PURPOSE |
| // is also a TREE_LIST with TREE_VALUE a string constant holding "=r". There |
| // are two inputs, "0" (x) and "g" (y), so gimple_asm_ninputs returns 2. The |
| // routine gimple_asm_input_op returns them in the same format as for outputs. |
| // The number of clobbers is returned by gimple_asm_nclobbers, 0 in this case. |
| // To get the clobbers use gimple_asm_clobber_op. This returns a TREE_LIST |
| // node with TREE_VALUE a string constant holding the clobber. To find out if |
| // the asm is volatile call gimple_asm_volatile_p, which returns true if so. |
| // See below for labels (this example does not have any). |
| |
| // Note that symbolic names have been substituted before getting here. For |
| // example this |
| // asm ("cmoveq %1,%2,%[result]" : [result] "=r"(result) |
| // : "r"(test), "r"(new), "[result]"(old)); |
| // turns up as |
| // asm ("cmoveq %1,%2,%0" : "=r"(result) : "r"(test), "r"(new), "0"(old)); |
| |
| // Note that clobbers may not turn up in the same order as in the original, eg |
| // asm volatile ("movc3 %0,%1,%2" : /* no outputs */ |
| // : "g" (from), "g" (to), "g" (count) |
| // : "r0", "r1", "r2", "r3", "r4", "r5"); |
| // The clobbers turn up as "r5", "r4", "r3", "r2", "r1", "r0". |
| |
| // Here is an example of the "asm goto" construct (not yet supported by LLVM): |
| // int frob(int x) { |
| // int y; |
| // asm goto ("frob %%r5, %1; jc %l[error]; mov (%2), %%r5" |
| // : : "r"(x), "r"(&y) : "r5", "memory" : error); |
| // return y; |
| // error: |
| // return -1; |
| // } |
| // The number of labels, one in this case, is returned by gimple_asm_nlabels. |
| // The labels themselves are returned by gimple_asm_label_op as a TREE_LIST |
| // node with TREE_PURPOSE a string constant holding the label name ("error") |
| // and TREE_VALUE holding the appropriate LABEL_DECL. |
| |
| // TODO: Add support for labels. |
| if (gimple_asm_nlabels(stmt) > 0) { |
| sorry("'asm goto' not supported"); |
| return; |
| } |
| |
| const unsigned NumOutputs = gimple_asm_noutputs(stmt); |
| const unsigned NumInputs = gimple_asm_ninputs(stmt); |
| const unsigned NumClobbers = gimple_asm_nclobbers(stmt); |
| |
| /// Constraints - The output/input constraints, concatenated together in array |
| /// form instead of list form. This way of doing things is forced on us by |
| /// GCC routines like parse_output_constraint which rummage around inside the |
| /// array. |
| const char **Constraints = (const char **)alloca( |
| (NumOutputs + NumInputs) * sizeof(const char *)); |
| |
| // Initialize the Constraints array. |
| for (unsigned i = 0; i != NumOutputs; ++i) { |
| tree Output = gimple_asm_output_op(stmt, i); |
| // If there's an erroneous arg then bail out. |
| if (TREE_TYPE(TREE_VALUE(Output)) == error_mark_node) |
| return; |
| // Record the output constraint. |
| const char *Constraint = |
| TREE_STRING_POINTER(TREE_VALUE(TREE_PURPOSE(Output))); |
| Constraints[i] = Constraint; |
| } |
| for (unsigned i = 0; i != NumInputs; ++i) { |
| tree Input = gimple_asm_input_op(stmt, i); |
| // If there's an erroneous arg then bail out. |
| if (TREE_TYPE(TREE_VALUE(Input)) == error_mark_node) |
| return; |
| // Record the input constraint. |
| const char *Constraint = |
| TREE_STRING_POINTER(TREE_VALUE(TREE_PURPOSE(Input))); |
| Constraints[NumOutputs + i] = Constraint; |
| } |
| |
| // Look for multiple alternative constraints: multiple alternatives separated |
| // by commas. |
| unsigned NumChoices = 0; // sentinal; real value is always at least 1. |
| for (unsigned i = 0; i != NumInputs; ++i) { |
| tree Input = gimple_asm_input_op(stmt, i); |
| unsigned NumInputChoices = 1; |
| for (const char * |
| p = TREE_STRING_POINTER(TREE_VALUE(TREE_PURPOSE(Input))); |
| * p; ++p) |
| if (*p == ',') |
| ++NumInputChoices; |
| if (NumChoices && (NumInputChoices != NumChoices)) { |
| error("operand constraints for %<asm%> differ in number of " |
| "alternatives"); |
| return; |
| } |
| if (NumChoices == 0) |
| NumChoices = NumInputChoices; |
| } |
| for (unsigned i = 0; i != NumOutputs; ++i) { |
| tree Output = gimple_asm_output_op(stmt, i); |
| unsigned NumOutputChoices = 1; |
| for (const char * |
| p = TREE_STRING_POINTER(TREE_VALUE(TREE_PURPOSE(Output))); |
| * p; ++p) |
| if (*p == ',') |
| ++NumOutputChoices; |
| if (NumChoices && (NumOutputChoices != NumChoices)) { |
| error("operand constraints for %<asm%> differ in number of " |
| "alternatives"); |
| return; |
| } |
| if (NumChoices == 0) |
| NumChoices = NumOutputChoices; |
| } |
| |
| // If there are multiple constraint tuples, pick one. Constraints is |
| // altered to point to shorter strings (which are malloc'ed), and everything |
| // below Just Works as in the NumChoices==1 case. |
| BumpPtrAllocator StringStorage(256, 256); |
| if (NumChoices > 1) |
| ChooseConstraintTuple(stmt, Constraints, NumChoices, StringStorage); |
| |
| // HasSideEffects - Whether the LLVM inline asm should be marked as having |
| // side effects. |
| bool HasSideEffects = gimple_asm_volatile_p(stmt) || (NumOutputs == 0); |
| |
| // CallResultTypes - The inline asm call may return one or more results. The |
| // types of the results are recorded here along with a flag indicating whether |
| // the corresponding GCC type is signed. |
| SmallVector<std::pair<Type *, bool>, 4> CallResultTypes; |
| |
| // CallResultDests - Each result returned by the inline asm call is stored in |
| // a memory location. These are listed here along with a flag indicating if |
| // the GCC type corresponding to the memory location is signed. The type of |
| // the memory location is allowed to differ from the type of the call result, |
| // in which case the result is converted before being stored. |
| SmallVector<std::pair<Value *, bool>, 4> CallResultDests; |
| |
| // CallOps - The operands pass to the inline asm call. |
| SmallVector<Value *, 16> CallOps; |
| |
| // OutputLocations - For each output holds an index into CallOps (if the flag |
| // is false) or into CallResultTypes (if the flag is true). Outputs returned |
| // in memory are passed to the asm as an operand and thus appear in CallOps. |
| // Those returned in registers are obtained as one of the results of the asm |
| // call and thus correspond to an entry in CallResultTypes. |
| SmallVector<std::pair<bool, unsigned>, 4> OutputLocations; |
| |
| // SSADefinitions - If the asm defines an SSA name then the SSA name and a |
| // memory location are recorded here. The asm result defining the SSA name |
| // will be stored to the memory memory location, and loaded out afterwards |
| // to define the SSA name. |
| SmallVector<std::pair<tree, MemRef>, 4> SSADefinitions; |
| |
| // ConstraintStr - The string of constraints in LLVM format. |
| std::string ConstraintStr; |
| |
| // Process outputs. |
| for (unsigned i = 0; i != NumOutputs; ++i) { |
| tree Output = gimple_asm_output_op(stmt, i); |
| tree Operand = TREE_VALUE(Output); |
| |
| // Parse the output constraint. |
| const char *Constraint = Constraints[i]; |
| bool IsInOut, AllowsReg, AllowsMem; |
| if (!parse_output_constraint(&Constraint, i, NumInputs, NumOutputs, |
| &AllowsMem, &AllowsReg, &IsInOut)) |
| return; |
| assert(Constraint[0] == '=' && "Not an output constraint?"); |
| assert(!IsInOut && "asm expression not gimplified?"); |
| |
| std::string SimplifiedConstraint; |
| // If this output register is pinned to a machine register, use that machine |
| // register instead of the specified constraint. |
| if (isa<VAR_DECL>(Operand) && DECL_HARD_REGISTER(Operand)) { |
| const char *RegName = extractRegisterName(Operand); |
| int RegNum = decode_reg_name(RegName); |
| if (RegNum >= 0) { |
| RegName = LLVM_GET_REG_NAME(RegName, RegNum); |
| size_t RegNameLen = strlen(RegName); |
| char *NewConstraint = (char *)alloca(RegNameLen + 3); |
| NewConstraint[0] = '{'; |
| memcpy(NewConstraint + 1, RegName, RegNameLen); |
| NewConstraint[RegNameLen + 1] = '}'; |
| NewConstraint[RegNameLen + 2] = 0; |
| SimplifiedConstraint = NewConstraint; |
| // This output will now be implicit; set the sideffect flag on the asm. |
| HasSideEffects = true; |
| // We should no longer consider mem constraints. |
| AllowsMem = false; |
| } else { |
| // If we can simplify the constraint into something else, do so now. |
| // This avoids LLVM having to know about all the (redundant) GCC |
| // constraints. |
| SimplifiedConstraint = CanonicalizeConstraint(Constraint + 1); |
| } |
| } else { |
| SimplifiedConstraint = CanonicalizeConstraint(Constraint + 1); |
| } |
| |
| LValue Dest; |
| Type *DestValTy = ConvertType(TREE_TYPE(Operand)); |
| if (isa<SSA_NAME>(Operand)) { |
| // The ASM is defining an ssa name. Store the output to a temporary, then |
| // load it out again later as the ssa name. |
| MemRef TmpLoc = CreateTempLoc(DestValTy); |
| SSADefinitions.push_back(std::make_pair(Operand, TmpLoc)); |
| Dest = LValue(TmpLoc); |
| } else { |
| Dest = EmitLV(Operand); |
| assert(cast<PointerType>(Dest.Ptr->getType())->getElementType() == |
| DestValTy && "LValue has wrong type!"); |
| } |
| |
| assert(!Dest.isBitfield() && "Cannot assign into a bitfield!"); |
| if (!AllowsMem && |
| DestValTy->isSingleValueType()) { // Reg dest -> asm return |
| ConstraintStr += ",="; |
| ConstraintStr += SimplifiedConstraint; |
| bool IsSigned = !TYPE_UNSIGNED(TREE_TYPE(Operand)); |
| CallResultDests.push_back(std::make_pair(Dest.Ptr, IsSigned)); |
| CallResultTypes.push_back(std::make_pair(DestValTy, IsSigned)); |
| OutputLocations.push_back( |
| std::make_pair(true, CallResultTypes.size() - 1)); |
| } else { |
| ConstraintStr += ",=*"; |
| ConstraintStr += SimplifiedConstraint; |
| CallOps.push_back(Dest.Ptr); |
| OutputLocations.push_back(std::make_pair(false, CallOps.size() - 1)); |
| } |
| } |
| |
| // Process inputs. |
| for (unsigned i = 0; i != NumInputs; ++i) { |
| tree Input = gimple_asm_input_op(stmt, i); |
| tree Val = TREE_VALUE(Input); |
| tree type = TREE_TYPE(Val); |
| bool IsSigned = !TYPE_UNSIGNED(type); |
| |
| const char *Constraint = Constraints[NumOutputs + i]; |
| |
| bool AllowsReg, AllowsMem; |
| if (!parse_input_constraint(Constraints + NumOutputs + i, i, NumInputs, |
| NumOutputs, 0, Constraints, &AllowsMem, |
| &AllowsReg)) |
| return; |
| bool isIndirect = false; |
| if (AllowsReg || !AllowsMem) { // Register operand. |
| Type *LLVMTy = ConvertType(type); |
| |
| Value *Op = 0; |
| Type *OpTy = LLVMTy; |
| if (LLVMTy->isSingleValueType()) { |
| if (isa<ADDR_EXPR>(Val) && isa<LABEL_DECL>(TREE_OPERAND(Val, 0))) { |
| // Emit the label, but do not assume it is going to be the target |
| // of an indirect branch. Having this logic here is a hack; there |
| // should be a bit in the label identifying it as in an asm. |
| Op = getLabelDeclBlock(TREE_OPERAND(Val, 0)); |
| } else if (isa<VAR_DECL>(Val) && DECL_HARD_REGISTER(Val)) { |
| // GCC special cases hard registers used as inputs to asm statements. |
| // Emit an inline asm node that copies the value out of the specified |
| // register. |
| assert(canEmitRegisterVariable(Val) && |
| "Cannot read hard register!"); |
| Op = EmitReadOfRegisterVariable(Val); |
| } else { |
| Op = EmitMemory(Val); |
| } |
| } else { |
| LValue LV = EmitLV(Val); |
| assert(!LV.isBitfield() && |
| "Inline asm can't have bitfield operand"); |
| |
| // Small structs and unions can be treated as integers. |
| uint64_t TySize = DL.getTypeSizeInBits(LLVMTy); |
| if (TySize == 1 || TySize == 8 || TySize == 16 || TySize == 32 || |
| TySize == 64 || (TySize == 128 && !AllowsMem)) { |
| LLVMTy = IntegerType::get(Context, (unsigned) TySize); |
| Op = Builder.CreateLoad( |
| Builder.CreateBitCast(LV.Ptr, LLVMTy->getPointerTo())); |
| } else { |
| // Codegen only supports indirect operands with mem constraints. |
| if (!AllowsMem) |
| error( |
| "aggregate does not match inline asm register constraint"); |
| // Otherwise, emit our value as a lvalue. |
| isIndirect = true; |
| Op = LV.Ptr; |
| OpTy = Op->getType(); |
| } |
| } |
| |
| // If this input operand is matching an output operand, e.g. '0', check if |
| // this is something that llvm supports. If the operand types are |
| // different, then emit an error if 1) one of the types is not integer or |
| // pointer, 2) if size of input type is larger than the output type. If |
| // the size of the integer input size is smaller than the integer output |
| // type, then cast it to the larger type and shift the value if the target |
| // is big endian. |
| if (ISDIGIT(Constraint[0])) { |
| unsigned Match = |
| (unsigned) atoi(Constraint); // Unsigned - no minus sign |
| // This output might have gotten put in either CallResult or CallArg |
| // depending whether it's a register or not. Find its type. |
| Type *OTy = 0; |
| unsigned OutputIndex = ~0U; |
| if (Match < OutputLocations.size()) { |
| // Indices here known to be within range. |
| OutputIndex = OutputLocations[Match].second; |
| if (OutputLocations[Match].first) |
| OTy = CallResultTypes[OutputIndex].first; |
| else { |
| OTy = CallOps[OutputIndex]->getType(); |
| assert(OTy->isPointerTy() && "Expected pointer type!"); |
| OTy = cast<PointerType>(OTy)->getElementType(); |
| } |
| } |
| if (OTy && OTy != OpTy) { |
| if (!OTy->isSingleValueType() || !OpTy->isSingleValueType()) { |
| error( |
| "unsupported inline asm: input constraint with a matching " |
| "output constraint of incompatible type!"); |
| return; |
| } |
| uint64_t OTyBits = DL.getTypeSizeInBits(OTy); |
| uint64_t OpTyBits = DL.getTypeSizeInBits(OpTy); |
| if (OTyBits == 0 || OpTyBits == 0) { |
| error( |
| "unsupported inline asm: input constraint with a matching " |
| "output constraint of incompatible type!"); |
| return; |
| } else if (OTyBits < OpTyBits) { |
| // The output is smaller than the input. |
| if (OutputLocations[Match].first && |
| !isOperandMentioned(stmt, Match)) { |
| // The output is a register and is not explicitly mentioned in the |
| // asm string. Use the input type for the output, and arrange for |
| // the result to be truncated to the original output type after |
| // the asm call. |
| CallResultTypes[OutputIndex] = std::make_pair(OpTy, IsSigned); |
| } else if (isa<Constant>(Op) && |
| !isOperandMentioned(stmt, NumOutputs + i)) { |
| // The input is a constant that is not explicitly mentioned in the |
| // asm string. Convert to the output type like in an assignment. |
| Op = CastToAnyType(Op, IsSigned, OTy, |
| CallResultTypes[OutputIndex].second); |
| } else { |
| error("unsupported inline asm: input constraint with a " |
| "matching " |
| "output constraint of incompatible type!"); |
| return; |
| } |
| } else if (OTyBits > OpTyBits) { |
| // The input is smaller than the output. If the input is explicitly |
| // mentioned in the asm string then we cannot safely promote it, so |
| // bail out. |
| if (isOperandMentioned(stmt, NumOutputs + i)) { |
| error("unsupported inline asm: input constraint with a " |
| "matching " |
| "output constraint of incompatible type!"); |
| return; |
| } |
| Op = CastToAnyType(Op, IsSigned, OTy, |
| CallResultTypes[OutputIndex].second); |
| } |
| } |
| } |
| |
| CallOps.push_back(Op); |
| } else { // Memory operand. |
| mark_addressable(TREE_VALUE(Input)); |
| isIndirect = true; |
| LValue Src = EmitLV(Val); |
| assert(!Src.isBitfield() && "Cannot read from a bitfield!"); |
| CallOps.push_back(Src.Ptr); |
| } |
| |
| ConstraintStr += ','; |
| if (isIndirect) |
| ConstraintStr += '*'; |
| |
| // If this input register is pinned to a machine register, use that machine |
| // register instead of the specified constraint. |
| if (isa<VAR_DECL>(Val) && DECL_HARD_REGISTER(Val)) { |
| const char *RegName = extractRegisterName(Val); |
| int RegNum = decode_reg_name(RegName); |
| if (RegNum >= 0) { |
| RegName = LLVM_GET_REG_NAME(RegName, RegNum); |
| ConstraintStr += '{'; |
| ConstraintStr += RegName; |
| ConstraintStr += '}'; |
| continue; |
| } |
| } |
| |
| // If there is a simpler form for the register constraint, use it. |
| std::string Simplified = CanonicalizeConstraint(Constraint); |
| ConstraintStr += Simplified; |
| } |
| |
| // Process clobbers. |
| |
| // Some targets automatically clobber registers across an asm. |
| tree Clobbers; |
| { |
| // Create input, output & clobber lists for the benefit of md_asm_clobbers. |
| tree outputs = NULL_TREE; |
| if (NumOutputs) { |
| tree t = outputs = gimple_asm_output_op(stmt, 0); |
| for (unsigned i = 1; i < NumOutputs; i++) { |
| TREE_CHAIN(t) = gimple_asm_output_op(stmt, i); |
| t = gimple_asm_output_op(stmt, i); |
| } |
| } |
| |
| tree inputs = NULL_TREE; |
| if (NumInputs) { |
| tree t = inputs = gimple_asm_input_op(stmt, 0); |
| for (unsigned i = 1; i < NumInputs; i++) { |
| TREE_CHAIN(t) = gimple_asm_input_op(stmt, i); |
| t = gimple_asm_input_op(stmt, i); |
| } |
| } |
| |
| tree clobbers = NULL_TREE; |
| if (NumClobbers) { |
| tree t = clobbers = gimple_asm_clobber_op(stmt, 0); |
| for (unsigned i = 1; i < NumClobbers; i++) { |
| TREE_CHAIN(t) = gimple_asm_clobber_op(stmt, i); |
| t = gimple_asm_clobber_op(stmt, i); |
| } |
| } |
| |
| Clobbers = targetm.md_asm_clobbers(outputs, inputs, clobbers); |
| } |
| |
| for (; Clobbers; Clobbers = TREE_CHAIN(Clobbers)) { |
| const char *RegName = TREE_STRING_POINTER(TREE_VALUE(Clobbers)); |
| int RegCode = decode_reg_name(RegName); |
| |
| switch (RegCode) { |
| case -1: // Nothing specified? |
| case -2: // Invalid. |
| error("unknown register name %qs in %<asm%>", RegName); |
| return; |
| case -3: // cc |
| ConstraintStr += ",~{cc}"; |
| break; |
| case -4: // memory |
| ConstraintStr += ",~{memory}"; |
| break; |
| default : // Normal register name. |
| assert(RegName && "Null register name successfully decoded!"); |
| RegName = LLVM_GET_REG_NAME(RegName, RegCode); |
| ConstraintStr += ",~{"; |
| ConstraintStr += RegName; |
| ConstraintStr += "}"; |
| break; |
| } |
| } |
| |
| // Compute the return type to use for the asm call. |
| Type *CallResultType; |
| switch (CallResultTypes.size()) { |
| // If there are no results then the return type is void! |
| case 0: |
| CallResultType = Type::getVoidTy(Context); |
| break; |
| // If there is one result then use the result's type as the return type. |
| case 1: |
| CallResultType = CallResultTypes[0].first; |
| break; |
| // If the asm returns multiple results then create a struct type with the |
| // result types as its fields, and use it for the return type. |
| default: |
| SmallVector<Type *, 4> Fields((unsigned) CallResultTypes.size()); |
| for (unsigned i = 0, e = (unsigned) CallResultTypes.size(); i != e; ++i) |
| Fields[i] = CallResultTypes[i].first; |
| CallResultType = StructType::get(Context, Fields); |
| break; |
| } |
| |
| // Compute the types of the arguments to the asm call. |
| SmallVector<Type *, 16> CallArgTypes((unsigned) CallOps.size()); |
| for (unsigned i = 0, e = (unsigned) CallOps.size(); i != e; ++i) |
| CallArgTypes[i] = CallOps[i]->getType(); |
| |
| // Get the type of the called asm "function". |
| FunctionType *FTy = |
| FunctionType::get(CallResultType, CallArgTypes, false); |
| |
| // Remove the leading comma if we have operands. |
| if (!ConstraintStr.empty()) |
| ConstraintStr.erase(ConstraintStr.begin()); |
| |
| // Make sure we're created a valid inline asm expression. |
| if (!InlineAsm::Verify(FTy, ConstraintStr)) { |
| error("Invalid or unsupported inline assembly!"); |
| return; |
| } |
| |
| std::string NewAsmStr = ConvertInlineAsmStr(stmt, NumOutputs + NumInputs); |
| Value *Asm = |
| InlineAsm::get(FTy, NewAsmStr, ConstraintStr, HasSideEffects); |
| CallInst *CV = Builder.CreateCall( |
| Asm, CallOps, CallResultTypes.empty() ? "" : "asmtmp"); |
| CV->setDoesNotThrow(); |
| if (gimple_has_location(stmt)) { |
| // Pass the location of the asm using a !srcloc metadata. |
| Constant *LocationCookie = Builder.getInt64(gimple_location(stmt)); |
| CV->setMetadata("srcloc", MDNode::get(Context, LocationCookie)); |
| } |
| |
| // If the call produces a value, store it into the destination. |
| for (unsigned i = 0, NumResults = (unsigned) CallResultTypes.size(); |
| i != NumResults; ++i) { |
| Value *Val = |
| NumResults == 1 ? CV |
| : Builder.CreateExtractValue(CV, i, "asmresult"); |
| bool ValIsSigned = CallResultTypes[i].second; |
| |
| Value *Dest = CallResultDests[i].first; |
| Type *DestTy = cast<PointerType>(Dest->getType())->getElementType(); |
| bool DestIsSigned = CallResultDests[i].second; |
| Val = CastToAnyType(Val, ValIsSigned, DestTy, DestIsSigned); |
| Builder.CreateStore(Val, Dest); |
| } |
| |
| // If the call defined any ssa names, associate them with their value. |
| for (unsigned i = 0, e = (unsigned) SSADefinitions.size(); i != e; ++i) { |
| tree Name = SSADefinitions[i].first; |
| MemRef Loc = SSADefinitions[i].second; |
| Value *Val = LoadRegisterFromMemory(Loc, TREE_TYPE(Name), 0, Builder); |
| DefineSSAName(Name, Val); |
| } |
| |
| // Give the backend a chance to upgrade the inline asm to LLVM code. This |
| // handles some common cases that LLVM has intrinsics for, e.g. x86 bswap -> |
| // llvm.bswap. |
| if (const TargetLowering *TLI = TheTarget->getTargetLowering()) |
| TLI->ExpandInlineAsm(CV); |
| } |
| |
| void TreeToLLVM::RenderGIMPLE_ASSIGN(gimple stmt) { |
| tree lhs = gimple_assign_lhs(stmt); |
| |
| #if (GCC_MINOR > 6) |
| // Assigning a right-hand side with TREE_CLOBBER_P says that the left-hand |
| // side is dead from this point on. Output an llvm.lifetime.end intrinsic. |
| if (get_gimple_rhs_class(gimple_expr_code(stmt)) == GIMPLE_SINGLE_RHS && |
| TREE_CLOBBER_P(gimple_assign_rhs1(stmt))) { |
| // Be conservative and only output the intrinsic if the left-hand side |
| // corresponds to some kind of concrete object. Note that we generate |
| // code to read from RESULT_DECLs before returning from the function, so |
| // saying that a RESULT_DECL is dead means we are dead - which is why we |
| // don't even consider it. |
| if (isa<PARM_DECL>(lhs) || isa<VAR_DECL>(lhs)) { |
| Value *LHSAddr = |
| Builder.CreateBitCast(DECL_LOCAL(lhs), Builder.getInt8PtrTy()); |
| uint64_t LHSSize = |
| isInt64(DECL_SIZE(lhs), true) ? getInt64(DECL_SIZE(lhs), true) / 8 |
| : ~0UL; |
| Function *EndIntr = |
| Intrinsic::getDeclaration(TheModule, Intrinsic::lifetime_end); |
| Builder.CreateCall2(EndIntr, Builder.getInt64(LHSSize), LHSAddr); |
| } |
| return; |
| } |
| #endif |
| |
| if (isa<AGGREGATE_TYPE>(TREE_TYPE(lhs))) { |
| assert(get_gimple_rhs_class(gimple_expr_code(stmt)) == |
| GIMPLE_SINGLE_RHS && "Aggregate type but rhs not simple!"); |
| LValue LV = EmitLV(lhs); |
| MemRef NewLoc(LV.Ptr, LV.getAlignment(), TREE_THIS_VOLATILE(lhs)); |
| EmitAggregate(gimple_assign_rhs1(stmt), NewLoc); |
| return; |
| } |
| WriteScalarToLHS(lhs, EmitAssignRHS(stmt)); |
| } |
| |
| void TreeToLLVM::RenderGIMPLE_CALL(gimple stmt) { |
| tree lhs = gimple_call_lhs(stmt); |
| if (!lhs) { |
| // The returned value is not used. |
| if (!isa<AGGREGATE_TYPE>(gimple_call_return_type(stmt))) { |
| OutputCallRHS(stmt, 0); |
| return; |
| } |
| // Create a temporary to hold the returned value. |
| // TODO: Figure out how to avoid creating this temporary and the |
| // associated useless code that stores the returned value into it. |
| MemRef Loc = CreateTempLoc(ConvertType(gimple_call_return_type(stmt))); |
| OutputCallRHS(stmt, &Loc); |
| return; |
| } |
| |
| if (isa<AGGREGATE_TYPE>(TREE_TYPE(lhs))) { |
| LValue LV = EmitLV(lhs); |
| MemRef NewLoc(LV.Ptr, LV.getAlignment(), TREE_THIS_VOLATILE(lhs)); |
| OutputCallRHS(stmt, &NewLoc); |
| return; |
| } |
| WriteScalarToLHS(lhs, OutputCallRHS(stmt, 0)); |
| } |
| |
| void TreeToLLVM::RenderGIMPLE_COND(gimple stmt) { |
| // Emit the comparison. |
| Value *Cond = EmitCompare(gimple_cond_lhs(stmt), gimple_cond_rhs(stmt), |
| gimple_cond_code(stmt)); |
| |
| // Extract the target basic blocks. |
| edge true_edge, false_edge; |
| extract_true_false_edges_from_block(gimple_bb(stmt), &true_edge, |
| &false_edge); |
| BasicBlock *IfTrue = getBasicBlock(true_edge->dest); |
| BasicBlock *IfFalse = getBasicBlock(false_edge->dest); |
| |
| // Branch based on the condition. |
| Builder.CreateCondBr(Cond, IfTrue, IfFalse); |
| } |
| |
| void TreeToLLVM::RenderGIMPLE_EH_DISPATCH(gimple stmt) { |
| int RegionNo = gimple_eh_dispatch_region(stmt); |
| eh_region region = get_eh_region_from_number(RegionNo); |
| |
| switch (region->type) { |
| default: |
| llvm_unreachable("Unexpected region type!"); |
| case ERT_ALLOWED_EXCEPTIONS: { |
| // Filter. |
| BasicBlock *Dest = getLabelDeclBlock(region->u.allowed.label); |
| |
| if (!region->u.allowed.type_list) { |
| // Not allowed to throw. Branch directly to the post landing pad. |
| Builder.CreateBr(Dest); |
| BeginBlock(BasicBlock::Create(Context)); |
| break; |
| } |
| |
| // The result of a filter selection will be a negative index if there is a |
| // match. |
| // FIXME: It looks like you have to compare against a specific value, |
| // checking for any old negative number is not enough! This should not |
| // matter if the failure code branched to on a filter match is always the |
| // same (as in C++), but might cause problems with other languages. |
| Value *Filter = Builder.CreateLoad(getExceptionFilter(RegionNo)); |
| |
| // Compare with the filter action value. |
| Value *Zero = ConstantInt::get(Filter->getType(), 0); |
| Value *Compare = Builder.CreateICmpSLT(Filter, Zero); |
| |
| // Branch on the compare. |
| BasicBlock *NoMatchBB = BasicBlock::Create(Context); |
| Builder.CreateCondBr(Compare, Dest, NoMatchBB); |
| BeginBlock(NoMatchBB); |
| break; |
| } |
| case ERT_TRY: |
| // Catches. |
| Value *Filter = NULL; |
| SmallSet<Value *, 8> AlreadyCaught; // Typeinfos known caught. |
| Function *TypeIDIntr = |
| Intrinsic::getDeclaration(TheModule, Intrinsic::eh_typeid_for); |
| for (eh_catch c = region->u.eh_try.first_catch; c; c = c->next_catch) { |
| BasicBlock *Dest = getLabelDeclBlock(c->label); |
| if (!c->type_list) { |
| // Catch-all. Branch directly to the post landing pad. |
| Builder.CreateBr(Dest); |
| break; |
| } |
| |
| Value *Cond = NULL; |
| for (tree type = c->type_list; type; type = TREE_CHAIN(type)) { |
| Value *TypeInfo = ConvertTypeInfo(TREE_VALUE(type)); |
| // No point in trying to catch a typeinfo that was already caught. |
| if (!AlreadyCaught.insert(TypeInfo)) |
| continue; |
| |
| TypeInfo = Builder.CreateBitCast(TypeInfo, Builder.getInt8PtrTy()); |
| |
| // Call get eh type id. |
| Value *TypeID = Builder.CreateCall(TypeIDIntr, TypeInfo, "typeid"); |
| |
| if (!Filter) |
| Filter = Builder.CreateLoad(getExceptionFilter(RegionNo)); |
| |
| // Compare with the exception selector. |
| Value *Compare = Builder.CreateICmpEQ(Filter, TypeID); |
| |
| Cond = Cond ? Builder.CreateOr(Cond, Compare) : Compare; |
| } |
| |
| if (Cond) { |
| BasicBlock *NoMatchBB = BasicBlock::Create(Context); |
| Builder.CreateCondBr(Cond, Dest, NoMatchBB); |
| BeginBlock(NoMatchBB); |
| } |
| } |
| break; |
| } |
| } |
| |
| void TreeToLLVM::RenderGIMPLE_GOTO(gimple stmt) { |
| tree dest = gimple_goto_dest(stmt); |
| |
| if (isa<LABEL_DECL>(dest)) { |
| // Direct branch. |
| Builder.CreateBr(getLabelDeclBlock(dest)); |
| return; |
| } |
| |
| // Indirect branch. |
| basic_block source = gimple_bb(stmt); |
| IndirectBrInst *Br = Builder.CreateIndirectBr(EmitRegister(dest), |
| EDGE_COUNT(source->succs)); |
| |
| // Add the list of possible destinations. |
| edge e; |
| edge_iterator ei; |
| FOR_EACH_EDGE(e, ei, source->succs) |
| Br->addDestination(getBasicBlock(e->dest)); |
| } |
| |
| void TreeToLLVM::RenderGIMPLE_RESX(gimple stmt) { |
| // Reraise an exception. If this statement is inside an exception handling |
| // region then the reraised exception may be caught by the current function, |
| // in which case it can be simplified into a branch. |
| int DstLPadNo = lookup_stmt_eh_lp(stmt); |
| eh_region dst_rgn = |
| DstLPadNo ? get_eh_region_from_lp_number(DstLPadNo) : NULL; |
| eh_region src_rgn = get_eh_region_from_number(gimple_resx_region(stmt)); |
| |
| if (!src_rgn) { |
| // Unreachable block? |
| Builder.CreateUnreachable(); |
| return; |
| } |
| |
| if (dst_rgn) { |
| if (DstLPadNo < 0) { |
| // The reraise is inside a must-not-throw region. Turn the reraise into a |
| // call to the failure routine (eg: std::terminate). |
| assert(dst_rgn->type == ERT_MUST_NOT_THROW && |
| "Unexpected region type!"); |
| |
| // Branch to the block containing the failure code. |
| Builder.CreateBr(getFailureBlock(dst_rgn->index)); |
| return; |
| } |
| |
| // Use the exception pointer and filter value for the source region as the |
| // values for the destination region. |
| Value *ExcPtr = Builder.CreateLoad(getExceptionPtr(src_rgn->index)); |
| Builder.CreateStore(ExcPtr, getExceptionPtr(dst_rgn->index)); |
| Value *Filter = Builder.CreateLoad(getExceptionFilter(src_rgn->index)); |
| Builder.CreateStore(Filter, getExceptionFilter(dst_rgn->index)); |
| |
| // Branch to the post landing pad for the destination region. |
| eh_landing_pad lp = get_eh_landing_pad_from_number(DstLPadNo); |
| assert(lp && "Post landing pad not found!"); |
| Builder.CreateBr(getLabelDeclBlock(lp->post_landing_pad)); |
| return; |
| } |
| |
| // Unwind the exception out of the function using a resume instruction. |
| Value *ExcPtr = Builder.CreateLoad(getExceptionPtr(src_rgn->index)); |
| Value *Filter = Builder.CreateLoad(getExceptionFilter(src_rgn->index)); |
| Type *UnwindDataTy = |
| StructType::get(Builder.getInt8PtrTy(), Builder.getInt32Ty(), NULL); |
| Value *UnwindData = UndefValue::get(UnwindDataTy); |
| UnwindData = Builder.CreateInsertValue(UnwindData, ExcPtr, 0, "exc_ptr"); |
| UnwindData = Builder.CreateInsertValue(UnwindData, Filter, 1, "filter"); |
| Builder.CreateResume(UnwindData); |
| } |
| |
| void TreeToLLVM::RenderGIMPLE_RETURN(gimple stmt) { |
| tree retval = gimple_return_retval(stmt); |
| tree result = DECL_RESULT(current_function_decl); |
| |
| if (retval && retval != error_mark_node && retval != result) { |
| // Store the return value to the function's DECL_RESULT. |
| MemRef DestLoc(DECL_LOCAL(result), 1, false); // FIXME: What alignment? |
| if (isa<AGGREGATE_TYPE>(TREE_TYPE(result))) { |
| EmitAggregate(retval, DestLoc); |
| } else { |
| Value *Val = Builder.CreateBitCast(EmitRegister(retval), |
| getRegType(TREE_TYPE(result))); |
| StoreRegisterToMemory(Val, DestLoc, TREE_TYPE(result), 0, Builder); |
| } |
| } |
| |
| // Emit a branch to the exit label. |
| if (!ReturnBB) |
| // Create a new block for the return node, but don't insert it yet. |
| ReturnBB = BasicBlock::Create(Context, "return"); |
| |
| Builder.CreateBr(ReturnBB); |
| } |
| |
| void TreeToLLVM::RenderGIMPLE_SWITCH(gimple stmt) { |
| // Emit the condition. |
| Value *Index = EmitRegister(gimple_switch_index(stmt)); |
| tree index_type = TREE_TYPE(gimple_switch_index(stmt)); |
| |
| // Create the switch instruction. |
| tree default_label = CASE_LABEL(gimple_switch_label(stmt, 0)); |
| SwitchInst *SI = |
| Builder.CreateSwitch(Index, getLabelDeclBlock(default_label), |
| gimple_switch_num_labels(stmt)); |
| |
| // Add the switch cases. |
| BasicBlock *IfBlock = 0; // Set if a range was output as an "if". |
| for (unsigned i = 1, e = gimple_switch_num_labels(stmt); i != e; ++i) { |
| tree label = gimple_switch_label(stmt, i); |
| BasicBlock *Dest = getLabelDeclBlock(CASE_LABEL(label)); |
| |
| // Convert the integer to the right type. |
| Value *Val = EmitRegisterWithCast(CASE_LOW(label), index_type); |
| ConstantInt *LowC = cast<ConstantInt>(Val); |
| |
| if (!CASE_HIGH(label)) { |
| SI->addCase(LowC, Dest); // Single destination. |
| continue; |
| } |
| |
| // Otherwise, we have a range, like 'case 1 ... 17'. |
| // Make sure the case value is the same type as the switch expression |
| Val = EmitRegisterWithCast(CASE_HIGH(label), index_type); |
| ConstantInt *HighC = cast<ConstantInt>(Val); |
| |
| APInt Range = HighC->getValue() - LowC->getValue(); |
| if (Range.ult(APInt(Range.getBitWidth(), 64))) { |
| // Add all of the necessary successors to the switch. |
| APInt CurrentValue = LowC->getValue(); |
| while (1) { |
| SI->addCase(LowC, Dest); |
| if (LowC == HighC) |
| break; // Emitted the last one. |
| CurrentValue++; |
| LowC = ConstantInt::get(Context, CurrentValue); |
| } |
| } else { |
| // The range is too big to add to the switch - emit an "if". |
| if (!IfBlock) { |
| IfBlock = BasicBlock::Create(Context); |
| BeginBlock(IfBlock); |
| } |
| Value *Diff = Builder.CreateSub(Index, LowC); |
| Value *Cond = |
| Builder.CreateICmpULE(Diff, ConstantInt::get(Context, Range)); |
| BasicBlock *False_Block = BasicBlock::Create(Context); |
| Builder.CreateCondBr(Cond, Dest, False_Block); |
| BeginBlock(False_Block); |
| } |
| } |
| |
| if (IfBlock) { |
| Builder.CreateBr(SI->getDefaultDest()); |
| SI->setDefaultDest(IfBlock); |
| } |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // ... Render helpers ... |
| //===----------------------------------------------------------------------===// |
| |
| /// EmitAssignRHS - Convert the RHS of a scalar GIMPLE_ASSIGN to LLVM. |
| Value *TreeToLLVM::EmitAssignRHS(gimple stmt) { |
| // Loads from memory and other non-register expressions are handled by |
| // EmitAssignSingleRHS. |
| if (get_gimple_rhs_class(gimple_expr_code(stmt)) == GIMPLE_SINGLE_RHS) { |
| Value *RHS = EmitAssignSingleRHS(gimple_assign_rhs1(stmt)); |
| assert(RHS->getType() == |
| getRegType(TREE_TYPE(gimple_assign_rhs1(stmt))) && |
| "RHS has wrong type!"); |
| return RHS; |
| } |
| |
| // The RHS is a register expression. Emit it now. |
| tree type = TREE_TYPE(gimple_assign_lhs(stmt)); |
| tree_code code = gimple_assign_rhs_code(stmt); |
| tree rhs1 = gimple_assign_rhs1(stmt); |
| tree rhs2 = gimple_assign_rhs2(stmt); |
| #if (GCC_MINOR > 6) |
| tree rhs3 = gimple_assign_rhs3(stmt); |
| #endif |
| |
| Value *RHS = 0; |
| switch (code) { |
| default: |
| debug_gimple_stmt(stmt); |
| llvm_unreachable("Unsupported GIMPLE assignment!"); |
| |
| // Unary expressions. |
| case ABS_EXPR: |
| RHS = EmitReg_ABS_EXPR(rhs1); |
| break; |
| case BIT_NOT_EXPR: |
| RHS = EmitReg_BIT_NOT_EXPR(rhs1); |
| break; |
| case CONJ_EXPR: |
| RHS = EmitReg_CONJ_EXPR(rhs1); |
| break; |
| case CONVERT_EXPR: |
| case FIX_TRUNC_EXPR: |
| case FLOAT_EXPR: |
| case NOP_EXPR: |
| RHS = EmitReg_CONVERT_EXPR(type, rhs1); |
| break; |
| case NEGATE_EXPR: |
| RHS = EmitReg_NEGATE_EXPR(rhs1); |
| break; |
| case PAREN_EXPR: |
| RHS = EmitReg_PAREN_EXPR(rhs1); |
| break; |
| case TRUTH_NOT_EXPR: |
| RHS = EmitReg_TRUTH_NOT_EXPR(type, rhs1); |
| break; |
| |
| // Comparisons. |
| case EQ_EXPR: |
| case GE_EXPR: |
| case GT_EXPR: |
| case LE_EXPR: |
| case LT_EXPR: |
| case LTGT_EXPR: |
| case NE_EXPR: |
| case ORDERED_EXPR: |
| case UNEQ_EXPR: |
| case UNGE_EXPR: |
| case UNGT_EXPR: |
| case UNLE_EXPR: |
| case UNLT_EXPR: |
| case UNORDERED_EXPR: |
| // The GCC result may be of any integer type. |
| RHS = |
| Builder.CreateZExt(EmitCompare(rhs1, rhs2, code), getRegType(type)); |
| break; |
| |
| // Binary expressions. |
| case BIT_AND_EXPR: |
| RHS = EmitReg_BIT_AND_EXPR(rhs1, rhs2); |
| break; |
| case BIT_IOR_EXPR: |
| RHS = EmitReg_BIT_IOR_EXPR(rhs1, rhs2); |
| break; |
| case BIT_XOR_EXPR: |
| RHS = EmitReg_BIT_XOR_EXPR(rhs1, rhs2); |
| break; |
| case CEIL_DIV_EXPR: |
| RHS = EmitReg_CEIL_DIV_EXPR(rhs1, rhs2); |
| break; |
| case COMPLEX_EXPR: |
| RHS = EmitReg_COMPLEX_EXPR(rhs1, rhs2); |
| break; |
| case EXACT_DIV_EXPR: |
| RHS = EmitReg_TRUNC_DIV_EXPR(rhs1, rhs2, /*isExact*/ true); |
| break; |
| case FLOOR_DIV_EXPR: |
| RHS = EmitReg_FLOOR_DIV_EXPR(rhs1, rhs2); |
| break; |
| case FLOOR_MOD_EXPR: |
| RHS = EmitReg_FLOOR_MOD_EXPR(rhs1, rhs2); |
| break; |
| case LROTATE_EXPR: |
| RHS = EmitReg_RotateOp(type, rhs1, rhs2, Instruction::Shl, |
| Instruction::LShr); |
| break; |
| case LSHIFT_EXPR: |
| RHS = EmitReg_ShiftOp(rhs1, rhs2, Instruction::Shl); |
| break; |
| case MAX_EXPR: |
| RHS = EmitReg_MinMaxExpr(rhs1, rhs2, ICmpInst::ICMP_UGE, |
| ICmpInst::ICMP_SGE, FCmpInst::FCMP_OGE); |
| break; |
| case MIN_EXPR: |
| RHS = EmitReg_MinMaxExpr(rhs1, rhs2, ICmpInst::ICMP_ULE, |
| ICmpInst::ICMP_SLE, FCmpInst::FCMP_OLE); |
| break; |
| case MINUS_EXPR: |
| RHS = EmitReg_MINUS_EXPR(rhs1, rhs2); |
| break; |
| case MULT_EXPR: |
| RHS = EmitReg_MULT_EXPR(rhs1, rhs2); |
| break; |
| case PLUS_EXPR: |
| RHS = EmitReg_PLUS_EXPR(rhs1, rhs2); |
| break; |
| case POINTER_PLUS_EXPR: |
| RHS = EmitReg_POINTER_PLUS_EXPR(rhs1, rhs2); |
| break; |
| case RDIV_EXPR: |
| RHS = EmitReg_RDIV_EXPR(rhs1, rhs2); |
| break; |
| case REDUC_MAX_EXPR: |
| RHS = EmitReg_ReducMinMaxExpr(rhs1, ICmpInst::ICMP_UGE, |
| ICmpInst::ICMP_SGE, FCmpInst::FCMP_OGE); |
| break; |
| case REDUC_MIN_EXPR: |
| RHS = EmitReg_ReducMinMaxExpr(rhs1, ICmpInst::ICMP_ULE, |
| ICmpInst::ICMP_SLE, FCmpInst::FCMP_OLE); |
| break; |
| case REDUC_PLUS_EXPR: |
| RHS = EmitReg_REDUC_PLUS_EXPR(rhs1); |
| break; |
| case ROUND_DIV_EXPR: |
| RHS = EmitReg_ROUND_DIV_EXPR(rhs1, rhs2); |
| break; |
| case RROTATE_EXPR: |
| RHS = EmitReg_RotateOp(type, rhs1, rhs2, Instruction::LShr, |
| Instruction::Shl); |
| break; |
| case RSHIFT_EXPR: |
| RHS = EmitReg_ShiftOp(rhs1, rhs2, |
| TYPE_UNSIGNED(type) ? Instruction::LShr |
| : Instruction::AShr); |
| break; |
| case TRUNC_DIV_EXPR: |
| RHS = EmitReg_TRUNC_DIV_EXPR(rhs1, rhs2, /*isExact*/ false); |
| break; |
| case TRUNC_MOD_EXPR: |
| RHS = EmitReg_TRUNC_MOD_EXPR(rhs1, rhs2); |
| break; |
| case TRUTH_AND_EXPR: |
| RHS = EmitReg_TruthOp(type, rhs1, rhs2, Instruction::And); |
| break; |
| case TRUTH_OR_EXPR: |
| RHS = EmitReg_TruthOp(type, rhs1, rhs2, Instruction::Or); |
| break; |
| case TRUTH_XOR_EXPR: |
| RHS = EmitReg_TruthOp(type, rhs1, rhs2, Instruction::Xor); |
| break; |
| #if (GCC_MINOR < 7) |
| case VEC_EXTRACT_EVEN_EXPR: |
| RHS = EmitReg_VEC_EXTRACT_EVEN_EXPR(rhs1, rhs2); |
| break; |
| case VEC_EXTRACT_ODD_EXPR: |
| RHS = EmitReg_VEC_EXTRACT_ODD_EXPR(rhs1, rhs2); |
| break; |
| case VEC_INTERLEAVE_HIGH_EXPR: |
| RHS = EmitReg_VEC_INTERLEAVE_HIGH_EXPR(rhs1, rhs2); |
| break; |
| case VEC_INTERLEAVE_LOW_EXPR: |
| RHS = EmitReg_VEC_INTERLEAVE_LOW_EXPR(rhs1, rhs2); |
| break; |
| #endif |
| case VEC_LSHIFT_EXPR: |
| RHS = EmitReg_VecShiftOp(rhs1, rhs2, /*isLeftShift*/ true); |
| break; |
| case VEC_PACK_FIX_TRUNC_EXPR: |
| case VEC_PACK_TRUNC_EXPR: |
| RHS = EmitReg_VEC_PACK_TRUNC_EXPR(type, rhs1, rhs2); |
| break; |
| case VEC_RSHIFT_EXPR: |
| RHS = EmitReg_VecShiftOp(rhs1, rhs2, /*isLeftShift*/ false); |
| break; |
| case VEC_UNPACK_FLOAT_HI_EXPR: |
| case VEC_UNPACK_HI_EXPR: |
| RHS = EmitReg_VecUnpackHiExpr(type, rhs1); |
| break; |
| case VEC_UNPACK_FLOAT_LO_EXPR: |
| case VEC_UNPACK_LO_EXPR: |
| RHS = EmitReg_VecUnpackLoExpr(type, rhs1); |
| break; |
| case VEC_WIDEN_MULT_HI_EXPR: |
| RHS = EmitReg_VEC_WIDEN_MULT_HI_EXPR(type, rhs1, rhs2); |
| break; |
| case VEC_WIDEN_MULT_LO_EXPR: |
| RHS = EmitReg_VEC_WIDEN_MULT_LO_EXPR(type, rhs1, rhs2); |
| break; |
| case WIDEN_MULT_EXPR: |
| RHS = EmitReg_WIDEN_MULT_EXPR(type, rhs1, rhs2); |
| break; |
| |
| // Ternary expressions. |
| #if (GCC_MINOR > 6) |
| case COND_EXPR: |
| case VEC_COND_EXPR: |
| RHS = EmitReg_CondExpr(rhs1, rhs2, rhs3); |
| break; |
| case VEC_PERM_EXPR: |
| RHS = EmitReg_VEC_PERM_EXPR(rhs1, rhs2, rhs3); |
| break; |
| #endif |
| } |
| |
| return TriviallyTypeConvert(RHS, getRegType(type)); |
| } |
| |
| /// EmitAssignSingleRHS - Helper for EmitAssignRHS. Handles those RHS that are |
| /// not register expressions. |
| Value *TreeToLLVM::EmitAssignSingleRHS(tree rhs) { |
| assert(!isa<AGGREGATE_TYPE>(TREE_TYPE(rhs)) && "Expected a scalar type!"); |
| |
| switch (TREE_CODE(rhs)) { |
| // Catch-all for SSA names, constants etc. |
| default: |
| return EmitRegister(rhs); |
| |
| // Expressions (tcc_expression). |
| case ADDR_EXPR: |
| return EmitADDR_EXPR(rhs); |
| #if (GCC_MINOR < 7) |
| case COND_EXPR: |
| case VEC_COND_EXPR: |
| return EmitCondExpr(rhs); |
| #endif |
| case OBJ_TYPE_REF: |
| return EmitOBJ_TYPE_REF(rhs); |
| |
| // Exceptional (tcc_exceptional). |
| case CONSTRUCTOR: |
| // Vector constant constructors are gimple invariant. |
| return is_gimple_constant(rhs) ? EmitRegisterConstant(rhs) |
| : EmitCONSTRUCTOR(rhs, 0); |
| |
| // References (tcc_reference). |
| case ARRAY_REF: |
| case ARRAY_RANGE_REF: |
| case BIT_FIELD_REF: |
| case COMPONENT_REF: |
| case IMAGPART_EXPR: |
| case INDIRECT_REF: |
| #if (GCC_MINOR > 5) |
| case MEM_REF: |
| #endif |
| #if (GCC_MINOR < 6) |
| case MISALIGNED_INDIRECT_REF: |
| #endif |
| case REALPART_EXPR: |
| case TARGET_MEM_REF: |
| case VIEW_CONVERT_EXPR: |
| return EmitLoadOfLValue(rhs); // Load from memory. |
| |
| // Declarations (tcc_declaration). |
| case PARM_DECL: |
| case RESULT_DECL: |
| case VAR_DECL: |
| return EmitLoadOfLValue(rhs); // Load from memory. |
| |
| // Constants (tcc_constant). |
| case STRING_CST: |
| return EmitLoadOfLValue(rhs); // Load from memory. |
| } |
| } |
| |
| /// OutputCallRHS - Convert the RHS of a GIMPLE_CALL. |
| Value *TreeToLLVM::OutputCallRHS(gimple stmt, const MemRef * DestLoc) { |
| // Check for a built-in function call. If we can lower it directly, do so |
| // now. |
| tree fndecl = gimple_call_fndecl(stmt); |
| if (fndecl && DECL_BUILT_IN(fndecl) && |
| DECL_BUILT_IN_CLASS(fndecl) != BUILT_IN_FRONTEND) { |
| Value *Res = 0; |
| if (EmitBuiltinCall(stmt, fndecl, DestLoc, Res)) |
| return Res ? Mem2Reg(Res, gimple_call_return_type(stmt), Builder) : 0; |
| } |
| |
| tree call_expr = gimple_call_fn(stmt); |
| assert(TREE_TYPE(call_expr) && |
| (isa<POINTER_TYPE>(TREE_TYPE(call_expr)) || |
| isa<REFERENCE_TYPE>(TREE_TYPE(call_expr))) && |
| "Not calling a function pointer?"); |
| |
| #if (GCC_MINOR < 7) |
| tree function_type = TREE_TYPE(TREE_TYPE(call_expr)); |
| #else |
| tree function_type = gimple_call_fntype(stmt); |
| #endif |
| Value *Callee = EmitRegister(call_expr); |
| CallingConv::ID CallingConv; |
| AttributeSet PAL; |
| |
| Type *Ty; |
| // If this is a K&R-style function: with a type that takes no arguments but |
| // with arguments none the less, then calculate the LLVM type from the list |
| // of arguments. |
| if (flag_functions_from_args) { |
| tree *FirstArgAddr = |
| gimple_call_num_args(stmt) > 0 ? gimple_call_arg_ptr(stmt, 0) |
| : NULL; |
| Ty = ConvertArgListToFnType( |
| function_type, |
| ArrayRef<tree>(FirstArgAddr, gimple_call_num_args(stmt)), |
| gimple_call_chain(stmt), !flag_functions_from_args, CallingConv, |
| PAL); |
| } else { |
| Ty = ConvertFunctionType(function_type, fndecl, gimple_call_chain(stmt), |
| CallingConv, PAL); |
| } |
| |
| // If this is a direct call to a function using a static chain then we need |
| // to ensure the function type is the one just calculated: it has an extra |
| // parameter for the chain. |
| Callee = Builder.CreateBitCast(Callee, Ty->getPointerTo()); |
| |
| Value *Result = EmitCallOf(Callee, stmt, DestLoc, PAL); |
| |
| // When calling a "noreturn" function output an unreachable instruction right |
| // after the function to prevent LLVM from thinking that control flow will |
| // fall into the subsequent block. |
| if (gimple_call_flags(stmt) & ECF_NORETURN) { |
| Builder.CreateUnreachable(); |
| BeginBlock(BasicBlock::Create(Context)); |
| } |
| |
| return Result ? Mem2Reg(Result, gimple_call_return_type(stmt), Builder) |
| : 0; |
| } |
| |
| /// WriteScalarToLHS - Store RHS, a non-aggregate value, into the given LHS. |
| void TreeToLLVM::WriteScalarToLHS(tree lhs, Value * RHS) { |
| tree type = TREE_TYPE(lhs); |
| |
| // May need a useless type conversion (useless_type_conversion_p). |
| RHS = TriviallyTypeConvert(RHS, getRegType(type)); |
| |
| // If this is the definition of an ssa name, record it in the SSANames map. |
| if (isa<SSA_NAME>(lhs)) { |
| if (flag_verbose_asm) |
| NameValue(RHS, lhs); |
| DefineSSAName(lhs, RHS); |
| return; |
| } |
| |
| if (canEmitRegisterVariable(lhs)) { |
| // If this is a store to a register variable, EmitLV can't handle the dest |
| // (there is no l-value of a register variable). Emit an inline asm node |
| // that copies the value into the specified register. |
| EmitModifyOfRegisterVariable(lhs, RHS); |
| return; |
| } |
| |
| LValue LV = EmitLV(lhs); |
| LV.Volatile = TREE_THIS_VOLATILE(lhs); |
| // TODO: Arrange for Volatile to already be set in the LValue. |
| if (!LV.isBitfield()) { |
| // Non-bitfield, scalar value. Just emit a store. |
| StoreRegisterToMemory(RHS, LV, type, describeAliasSet(lhs), Builder); |
| return; |
| } |
| |
| // Last case, this is a store to a bitfield, so we have to emit a |
| // read/modify/write sequence. |
| if (!LV.BitSize) |
| return; |
| |
| // Load and store the minimum number of bytes that covers the field. |
| unsigned LoadSizeInBits = LV.BitStart + LV.BitSize; |
| LoadSizeInBits = |
| (unsigned) RoundUpToAlignment(LoadSizeInBits, BITS_PER_UNIT); |
| Type *LoadType = IntegerType::get(Context, LoadSizeInBits); |
| |
| // Load the existing bits. |
| Value *Ptr = Builder.CreateBitCast(LV.Ptr, LoadType->getPointerTo()); |
| Value *Val = |
| Builder.CreateAlignedLoad(Ptr, LV.getAlignment(), LV.Volatile); |
| |
| // Turn RHS into a bunch of bits by storing it to a temporary then loading it |
| // out again as an integer. The temporary needs to be big enough to hold the |
| // in-memory representation of RHS. If the bitfield is wider than this (which |
| // only happens for non C-like languages) then any extra bits are undefined. |
| // We tell the optimizers that they are undefined by widening the temporary to |
| // at least the bitfield size but not storing anything to the extra bits. |
| unsigned MemSize = GET_MODE_BITSIZE(TYPE_MODE(type)); |
| unsigned TmpSize = std::max(LoadSizeInBits, MemSize); |
| Type *TmpType = IntegerType::get(Context, TmpSize); |
| |
| // Create the temporary, an integer. Ensure it is aligned enough for both RHS |
| // and the integer version of RHS. |
| unsigned Alignment = std::max(TYPE_ALIGN(type) / 8, |
| DL.getPrefTypeAlignment(TmpType)); |
| Value *Tmp = CreateTemporary(TmpType, Alignment); |
| |
| // Store the right-hand side to it. Ensure that any extra bits turn up in the |
| // high bits of the integer loaded out below. |
| MemRef TmpLoc(Tmp, Alignment, false); |
| if (BYTES_BIG_ENDIAN && MemSize < LoadSizeInBits) { |
| unsigned BitOffset = LoadSizeInBits - MemSize; |
| assert(BitOffset % BITS_PER_UNIT == 0 && "Mode size not round?"); |
| TmpLoc = DisplaceLocationByUnits(TmpLoc, BitOffset/BITS_PER_UNIT, Builder); |
| } |
| StoreRegisterToMemory(RHS, TmpLoc, type, 0, Builder); |
| |
| // Load it out again as an integer. Only the first LV.BitSize bits of this |
| // integer will be used (see the masking below). For C-like languages, the |
| // original RHS is always an integer that is at least as wide as LV.BitSize, |
| // so the used bits are just the original integer truncated to be LV.BitSize |
| // bits wide. |
| RHS = Builder.CreateIntCast(Builder.CreateLoad(Tmp), LoadType, |
| !TYPE_UNSIGNED(type)); |
| |
| // Shift the right-hand side so that its bits are in the right position. |
| unsigned FirstBitInVal = |
| BYTES_BIG_ENDIAN ? LoadSizeInBits - LV.BitStart - LV.BitSize |
| : LV.BitStart; |
| if (FirstBitInVal) { |
| Value *ShAmt = ConstantInt::get(LoadType, FirstBitInVal); |
| RHS = Builder.CreateShl(RHS, ShAmt); |
| } |
| // Mask out any bits in the right-hand side that shouldn't be in the result. |
| // The lower bits are zero already, so this only changes bits off the end. |
| APInt Mask = APInt::getBitsSet(LoadSizeInBits, FirstBitInVal, |
| FirstBitInVal + LV.BitSize); |
| if (FirstBitInVal + LV.BitSize != LoadSizeInBits) |
| RHS = Builder.CreateAnd(RHS, ConstantInt::get(Context, Mask)); |
| |
| // Mask out those bits in the original value that are being replaced by the |
| // right-hand side. |
| Val = Builder.CreateAnd(Val, ConstantInt::get(Context, ~Mask)); |
| |
| // Finally, merge the two together and store it. |
| Val = Builder.CreateOr(Val, RHS); |
| Builder.CreateAlignedStore(Val, Ptr, LV.getAlignment(), LV.Volatile); |
| } |