blob: 1c7dfec9ee37f20743c5e8ee987c3636f79bd20b [file] [log] [blame]
//==----- Target.h - Target hooks for GCC to LLVM conversion -----*- C++ -*-==//
//
// Copyright (C) 2007 to 2013 Anton Korobeynikov, 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 file declares some target-specific hooks for GCC to LLVM conversion.
//===----------------------------------------------------------------------===//
#ifndef DRAGONEGG_TARGET_H
#define DRAGONEGG_TARGET_H
namespace llvm { class SubtargetFeatures; }
/* LLVM specific stuff for supporting calling convention output */
#define TARGET_ADJUST_LLVM_CC(CC, type) \
{ \
tree_node *type_attributes = TYPE_ATTRIBUTES(type); \
if (lookup_attribute("stdcall", type_attributes)) { \
CC = CallingConv::X86_StdCall; \
} else if (lookup_attribute("fastcall", type_attributes)) { \
CC = CallingConv::X86_FastCall; \
} \
}
#define TARGET_ADJUST_LLVM_RETATTR(type, AttrBuilder) \
{ \
tree_node *type_attributes = TYPE_ATTRIBUTES(type); \
if (!TARGET_64BIT && (TARGET_SSEREGPARM || \
lookup_attribute("sseregparm", type_attributes))) \
AttrBuilder.addAttribute(Attribute::InReg); \
}
/* LLVM specific stuff for converting gcc's `regparm` attribute to LLVM's
`inreg` parameter attribute */
#define LLVM_TARGET_ENABLE_REGPARM
#include "auto-host.h"
#ifndef ENABLE_BUILD_WITH_CXX
extern "C" {
#endif
extern int ix86_regparm;
#ifndef ENABLE_BUILD_WITH_CXX
} // extern "C"
#endif
#define LLVM_TARGET_INIT_REGPARM(local_regparm, local_fp_regparm, type) \
{ \
tree_node *attr; \
local_regparm = ix86_regparm; \
local_fp_regparm = TARGET_SSEREGPARM ? 3 : 0; \
attr = lookup_attribute("regparm", TYPE_ATTRIBUTES(type)); \
if (attr) { \
local_regparm = TREE_INT_CST_LOW(TREE_VALUE(TREE_VALUE(attr))); \
} \
attr = lookup_attribute("sseregparm", TYPE_ATTRIBUTES(type)); \
if (attr) \
local_fp_regparm = 3; \
}
#define LLVM_ADJUST_REGPARM_ATTRIBUTE(AttrBuilder, Type, Size, local_regparm, \
local_fp_regparm) \
{ \
if (!TARGET_64BIT) { \
if (isa<REAL_TYPE>(Type) && \
(TYPE_PRECISION(Type) == 32 || TYPE_PRECISION(Type) == 64)) { \
local_fp_regparm -= 1; \
if (local_fp_regparm >= 0) \
AttrBuilder.addAttribute(Attribute::InReg); \
else \
local_fp_regparm = 0; \
} else if (isa<INTEGRAL_TYPE>(Type) || isa<ACCESS_TYPE>(Type)) { \
int words = (Size + BITS_PER_WORD - 1) / BITS_PER_WORD; \
local_regparm -= words; \
if (local_regparm >= 0) \
AttrBuilder.addAttribute(Attribute::InReg); \
else \
local_regparm = 0; \
} \
} \
}
#define LLVM_SET_RED_ZONE_FLAG(disable_red_zone) \
if (TARGET_64BIT && TARGET_NO_RED_ZONE) \
disable_red_zone = 1;
#ifdef DRAGONEGG_ABI_H
/* On x86-32 objects containing SSE vectors are 16 byte aligned, everything
else 4. On x86-64 vectors are 8-byte aligned, everything else can
be figured out by the back end. */
#define LLVM_BYVAL_ALIGNMENT(T) (TYPE_ALIGN(T) / 8)
extern tree_node *llvm_x86_should_return_selt_struct_as_scalar(tree_node *);
/* Structs containing a single data field plus zero-length fields are
considered as if they were the type of the data field. On x86-64,
if the element type is an MMX vector, return it as double (which will
get it into XMM0). */
#define LLVM_SHOULD_RETURN_SELT_STRUCT_AS_SCALAR(X) \
llvm_x86_should_return_selt_struct_as_scalar((X))
extern bool llvm_x86_should_pass_aggregate_in_integer_regs(tree_node *,
unsigned *, bool *);
/* LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS - Return true if this aggregate
value should be passed in integer registers. This differs from the usual
handling in that x86-64 passes 128-bit structs and unions which only
contain data in the first 64 bits, as 64-bit objects. (These can be
created by abusing __attribute__((aligned)). */
#define LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS(X, Y, Z) \
llvm_x86_should_pass_aggregate_in_integer_regs((X), (Y), (Z))
extern llvm::Type *
llvm_x86_scalar_type_for_struct_return(tree_node *type, unsigned *Offset);
/* LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN - Return LLVM Type if X can be
returned as a scalar, otherwise return NULL. */
#define LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN(X, Y) \
llvm_x86_scalar_type_for_struct_return((X), (Y))
extern llvm::Type *llvm_x86_aggr_type_for_struct_return(tree_node *type);
/* LLVM_AGGR_TYPE_FOR_STRUCT_RETURN - Return LLVM Type if X can be
returned as an aggregate, otherwise return NULL. */
#define LLVM_AGGR_TYPE_FOR_STRUCT_RETURN(X, CC) \
llvm_x86_aggr_type_for_struct_return(X)
extern void llvm_x86_extract_multiple_return_value(
llvm::Value *Src, llvm::Value *Dest, bool isVolatile, LLVMBuilder &B);
/* LLVM_EXTRACT_MULTIPLE_RETURN_VALUE - Extract multiple return value from
SRC and assign it to DEST. */
#define LLVM_EXTRACT_MULTIPLE_RETURN_VALUE(Src, Dest, V, B) \
llvm_x86_extract_multiple_return_value((Src), (Dest), (V), (B))
extern bool llvm_x86_should_pass_vector_using_byval_attr(tree_node *);
/* On x86-64, vectors which are not MMX nor SSE should be passed byval. */
#define LLVM_SHOULD_PASS_VECTOR_USING_BYVAL_ATTR(X) \
llvm_x86_should_pass_vector_using_byval_attr((X))
extern bool llvm_x86_should_pass_vector_in_integer_regs(tree_node *);
/* On x86-32, vectors which are not MMX nor SSE should be passed as integers. */
#define LLVM_SHOULD_PASS_VECTOR_IN_INTEGER_REGS(X) \
llvm_x86_should_pass_vector_in_integer_regs((X))
extern tree_node *llvm_x86_should_return_vector_as_scalar(tree_node *, bool);
/* The MMX vector v1i64 is returned in EAX and EDX on Darwin. Communicate
this by returning i64 here. Likewise, (generic) vectors such as v2i16
are returned in EAX.
On Darwin x86-64, MMX vectors are returned in XMM0. Communicate this by
returning f64. */
#define LLVM_SHOULD_RETURN_VECTOR_AS_SCALAR(X, isBuiltin) \
llvm_x86_should_return_vector_as_scalar((X), (isBuiltin))
extern bool llvm_x86_should_return_vector_as_shadow(tree_node *, bool);
/* MMX vectors v2i32, v4i16, v8i8, v2f32 are returned using sret on Darwin
32-bit. Vectors bigger than 128 are returned using sret. */
#define LLVM_SHOULD_RETURN_VECTOR_AS_SHADOW(X, isBuiltin) \
llvm_x86_should_return_vector_as_shadow((X), (isBuiltin))
extern bool llvm_x86_should_not_return_complex_in_memory(tree_node *type);
/* LLVM_SHOULD_NOT_RETURN_COMPLEX_IN_MEMORY - A hook to allow
special _Complex handling. Return true if X should be returned using
multiple value return instruction. */
#define LLVM_SHOULD_NOT_RETURN_COMPLEX_IN_MEMORY(X) \
llvm_x86_should_not_return_complex_in_memory((X))
extern bool llvm_x86_should_pass_aggregate_as_fca(tree_node *type,
llvm::Type *);
/* LLVM_SHOULD_PASS_AGGREGATE_AS_FCA - Return true if an aggregate of the
specified type should be passed as a first-class aggregate. */
#ifndef LLVM_SHOULD_PASS_AGGREGATE_AS_FCA
#define LLVM_SHOULD_PASS_AGGREGATE_AS_FCA(X, TY) \
llvm_x86_should_pass_aggregate_as_fca(X, TY)
#endif
extern bool llvm_x86_should_pass_aggregate_in_memory(tree_node *, llvm::Type *);
#define LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(X, TY) \
llvm_x86_should_pass_aggregate_in_memory(X, TY)
extern bool llvm_x86_64_should_pass_aggregate_in_mixed_regs(
tree_node *, llvm::Type *Ty, std::vector<llvm::Type *> &);
extern bool llvm_x86_32_should_pass_aggregate_in_mixed_regs(
tree_node *, llvm::Type *Ty, std::vector<llvm::Type *> &);
#define LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(T, TY, CC, E) \
(TARGET_64BIT \
? llvm_x86_64_should_pass_aggregate_in_mixed_regs((T), (TY), (E)) \
: llvm_x86_32_should_pass_aggregate_in_mixed_regs((T), (TY), (E)))
extern bool llvm_x86_64_aggregate_partially_passed_in_regs(
std::vector<llvm::Type *> &, std::vector<llvm::Type *> &, bool);
#define LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(E, SE, ISR, CC) \
(TARGET_64BIT \
? llvm_x86_64_aggregate_partially_passed_in_regs((E), (SE), (ISR)) \
: false)
#endif /* DRAGONEGG_ABI_H */
/* Register class used for passing given 64bit part of the argument.
These represent classes as documented by the PS ABI, with the exception
of SSESF, SSEDF classes, that are basically SSE class, just gcc will
use SF or DFmode move instead of DImode to avoid reformatting penalties.
Similarly we play games with INTEGERSI_CLASS to use cheaper SImode moves
whenever possible (upper half does contain padding).
*/
enum x86_64_reg_class {
X86_64_NO_CLASS,
X86_64_INTEGER_CLASS,
X86_64_INTEGERSI_CLASS,
X86_64_SSE_CLASS,
X86_64_SSESF_CLASS,
X86_64_SSEDF_CLASS,
X86_64_SSEUP_CLASS,
X86_64_X87_CLASS,
X86_64_X87UP_CLASS,
X86_64_COMPLEX_X87_CLASS,
X86_64_MEMORY_CLASS
};
/* LLVM_TARGET_INTRINSIC_PREFIX - Specify what prefix this target uses for its
* intrinsics.
*/
#define LLVM_TARGET_INTRINSIC_PREFIX "x86"
/* LLVM_TARGET_NAME - This specifies the name of the target, which correlates to
* the llvm::InitializeXXXTarget() function.
*/
#define LLVM_TARGET_NAME X86
/* Turn -march=xx into a CPU type.
*/
extern void llvm_x86_set_subtarget_features(std::string &C,
llvm::SubtargetFeatures &F);
#define LLVM_SET_SUBTARGET_FEATURES(C, F) llvm_x86_set_subtarget_features(C, F)
#define LLVM_SET_IMPLICIT_FLOAT(flag_no_implicit_float) \
if (!TARGET_80387) \
flag_no_implicit_float = 1; \
else \
flag_no_implicit_float = 0;
/* LLVM ABI definition macros. */
/* When -m64 is specified, set the architecture to x86_64-os-blah even if the
* compiler was configured for i[3456]86-os-blah.
*/
#define LLVM_OVERRIDE_TARGET_ARCH() (TARGET_64BIT ? "x86_64" : "i386")
extern const char *llvm_x86_override_target_environment();
#define LLVM_OVERRIDE_TARGET_ENVIRONMENT() \
llvm_x86_override_target_environment()
#define LLVM_ASM_EXTENSIONS(ESCAPED_CHAR, ASM, RESULT) \
else if ((ESCAPED_CHAR) == 'v') { \
/* %v means to use the AVX prefix 'v' if TARGET_AVX is true. */ \
if (TARGET_AVX) \
Result += 'v'; \
}
/* LLVM_TARGET_INTRINSIC_LOWER - To handle builtins, we want to expand the
* invocation into normal LLVM code. If the target can handle the builtin, this
* macro should call the target TreeToLLVM::TargetIntrinsicLower method and
* return true.This macro is invoked from a method in the TreeToLLVM class.
*/
#define LLVM_TARGET_INTRINSIC_LOWER(STMT, FNDECL, DESTLOC, RESULT, DESTTY, \
OPS) \
TargetIntrinsicLower(STMT, FNDECL, DESTLOC, RESULT, DESTTY, OPS);
/* LLVM_GET_REG_NAME - When extracting a register name for a constraint, use
the string extracted from the magic symbol built for that register, rather
than reg_names. The latter maps both AH and AL to the same thing, which
means we can't distinguish them. */
#define LLVM_GET_REG_NAME(REG_NAME, REG_NUM) \
__extension__({ \
const char *nm = (REG_NAME); \
if (nm && (*nm == '%' || *nm == '#')) \
++nm; \
((!nm || ISDIGIT(*nm)) ? reg_names[REG_NUM] : nm); \
})
/* LLVM_CANONICAL_ADDRESS_CONSTRAINTS - Valid x86 memory addresses include
symbolic values and immediates. Canonicalize GCC's "p" constraint for
memory addresses to allow both memory and immediate operands. */
#define LLVM_CANONICAL_ADDRESS_CONSTRAINTS "im"
/* Propagate code model setting to backend */
#define LLVM_SET_CODE_MODEL(CMModel) \
switch (ix86_cmodel) { \
case CM_32: \
CMModel = CodeModel::Default; \
break; \
case CM_SMALL: \
case CM_SMALL_PIC: \
CMModel = CodeModel::Small; \
break; \
case CM_KERNEL: \
CMModel = CodeModel::Kernel; \
break; \
case CM_MEDIUM: \
case CM_MEDIUM_PIC: \
CMModel = CodeModel::Medium; \
break; \
case CM_LARGE: \
case CM_LARGE_PIC: \
CMModel = CodeModel::Large; \
break; \
}
#define LLVM_SET_MACHINE_OPTIONS(argvec) \
do { \
if (ix86_force_align_arg_pointer) \
argvec.push_back("-force-align-stack"); \
} while (0)
#define LLVM_SET_TARGET_MACHINE_OPTIONS(O) \
do { \
if (TARGET_OMIT_LEAF_FRAME_POINTER) \
O.NoFramePointerElim = false; \
} while (0)
#define LLVM_SET_TARGET_MACHINE_ATTRIBUTES(F) \
do { \
if (TARGET_OMIT_LEAF_FRAME_POINTER) \
F->addFnAttr("no-frame-pointer-elim-non-leaf", "true"); \
} while (0)
#endif /* DRAGONEGG_TARGET_H */