Revision: 129555 Author: clattner Date: 2007-07-14 11:39:13 -0700 (Sat, 14 Jul 2007)
Log Message: ----------- Implement missing dwarf builtins, used by the libstdc++ unwinder. This is more or less workable on x86-32/linux only Patch by Anton Korobeynikov Modified Paths: -------------- apple-local/branches/llvm/gcc/llvm-convert.cpp apple-local/branches/llvm/gcc/llvm-internal.h Modified: apple-local/branches/llvm/gcc/llvm-convert.cpp =================================================================== --- apple-local/branches/llvm/gcc/llvm-convert.cpp 2007-07-14 07:20:19 UTC (rev 129554) +++ apple-local/branches/llvm/gcc/llvm-convert.cpp 2007-07-14 18:39:13 UTC (rev 129555) @@ -59,8 +59,10 @@ #include "target.h" #include "hard-reg-set.h" #include "except.h" +#include "rtl.h" extern bool tree_could_throw_p(tree); // tree-flow.h uses non-C++ C constructs. extern int get_pointer_alignment (tree exp, unsigned int max_align); +extern enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER]; } #define ITANIUM_STYLE_EXCEPTIONS @@ -4140,7 +4142,25 @@ return EmitBuiltinExtractReturnAddr(exp, Result); case BUILT_IN_FROB_RETURN_ADDR: return EmitBuiltinFrobReturnAddr(exp, Result); - + + // Builtins used by the exception handling runtime. + case BUILT_IN_DWARF_CFA: + return EmitBuiltinDwarfCFA(exp, Result); +#ifdef DWARF2_UNWIND_INFO + case BUILT_IN_DWARF_SP_COLUMN: + return EmitBuiltinDwarfSPColumn(exp, Result); + case BUILT_IN_INIT_DWARF_REG_SIZES: + return EmitBuiltinInitDwarfRegSizes(exp, Result); +#endif + case BUILT_IN_EH_RETURN: + return EmitBuiltinEHReturn(exp, Result); +#ifdef EH_RETURN_DATA_REGNO + case BUILT_IN_EH_RETURN_DATA_REGNO: + return EmitBuiltinEHReturnDataRegno(exp, Result); +#endif + case BUILT_IN_UNWIND_INIT: + return EmitBuiltinUnwindInit(exp, Result); + #define HANDLE_UNARY_FP(F32, F64, V) \ Result = EmitBuiltinUnaryFPOp(V, Intrinsic::F32, Intrinsic::F64) @@ -4216,19 +4236,8 @@ case BUILT_IN_LONGJMP: case BUILT_IN_UPDATE_SETJMP_BUF: case BUILT_IN_TRAP: - - // Various hooks for the DWARF 2 __throw routine. - case BUILT_IN_UNWIND_INIT: - case BUILT_IN_DWARF_CFA: -#ifdef DWARF2_UNWIND_INFO - case BUILT_IN_DWARF_SP_COLUMN: - case BUILT_IN_INIT_DWARF_REG_SIZES: -#endif - case BUILT_IN_EH_RETURN: -#ifdef EH_RETURN_DATA_REGNO - case BUILT_IN_EH_RETURN_DATA_REGNO: -#endif - // FIXME: HACK: Just ignore these. + + // FIXME: HACK: Just ignore these. { const Type *Ty = ConvertType(TREE_TYPE(exp)); if (Ty != Type::VoidTy) @@ -4509,6 +4518,171 @@ 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(tree exp, Value *&Result) { + if (!validate_arglist(TREE_OPERAND(exp, 1), VOID_TYPE)) + return false; + + int cfa_offset = ARG_POINTER_CFA_OFFSET(0); + + Result = Builder.CreateCall(Intrinsic::getDeclaration(TheModule, + Intrinsic::eh_dwarf_cfa), + ConstantInt::get(Type::Int32Ty, cfa_offset)); + + return true; +} + +bool TreeToLLVM::EmitBuiltinDwarfSPColumn(tree exp, Value *&Result) { + if (!validate_arglist(TREE_OPERAND(exp, 1), VOID_TYPE)) + return false; + + unsigned int dwarf_regnum = DWARF_FRAME_REGNUM(STACK_POINTER_REGNUM); + Result = ConstantInt::get(ConvertType(TREE_TYPE(exp)), dwarf_regnum); + + return true; +} + +bool TreeToLLVM::EmitBuiltinEHReturnDataRegno(tree exp, Value *&Result) { + tree arglist = TREE_OPERAND(exp, 1); + + if (!validate_arglist(arglist, INTEGER_TYPE, VOID_TYPE)) + return false; + + tree which = TREE_VALUE (arglist); + unsigned HOST_WIDE_INT iwhich; + + if (TREE_CODE (which) != INTEGER_CST) { + 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(TREE_TYPE(exp)), iwhich); + + return true; +} + +bool TreeToLLVM::EmitBuiltinEHReturn(tree exp, Value *&Result) { + tree arglist = TREE_OPERAND(exp, 1); + + if (!validate_arglist(arglist, INTEGER_TYPE, POINTER_TYPE, VOID_TYPE)) + return false; + + Value *Offset = Emit(TREE_VALUE(arglist), 0); + Value *Handler = Emit(TREE_VALUE(TREE_CHAIN(arglist)), 0); + Offset = Builder.CreateIntCast(Offset, Type::Int32Ty, true, "tmp"); + Handler = CastToType(Instruction::BitCast, Handler, + PointerType::get(Type::Int8Ty)); + + Builder.CreateCall(Intrinsic::getDeclaration(TheModule, + Intrinsic::eh_return), + Offset, Handler); + Result = Builder.CreateUnreachable(); + + return true; +} + +bool TreeToLLVM::EmitBuiltinInitDwarfRegSizes(tree exp, Value *&Result) { + unsigned int i; + bool wrote_return_column = false; + static bool reg_modes_initialized = false; + + tree arglist = TREE_OPERAND(exp, 1); + if (!validate_arglist(arglist, POINTER_TYPE, VOID_TYPE)) + return false; + + if (!reg_modes_initialized) { + init_reg_modes_once(); + reg_modes_initialized = true; + } + + Value *Addr = BitCastToType(Emit(TREE_VALUE(arglist), 0), + PointerType::get(Type::Int8Ty)); + 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 = ConstantInt::get(Type::Int8Ty, size); + Idx = ConstantInt::get(Type::Int32Ty, rnum); + Builder.CreateStore(Size, Builder.CreateGEP(Addr, Idx, "tmp"), false); + } + } + + if (!wrote_return_column) { + Size = ConstantInt::get(Type::Int8Ty, GET_MODE_SIZE (Pmode)); + Idx = ConstantInt::get(Type::Int32Ty, DWARF_FRAME_RETURN_COLUMN); + Builder.CreateStore(Size, Builder.CreateGEP(Addr, Idx, "tmp"), false); + } + +#ifdef DWARF_ALT_FRAME_RETURN_COLUMN + Size = ConstantInt::get(Type::Int8Ty, GET_MODE_SIZE (Pmode)); + Idx = ConstantInt::get(Type::Int32Ty, DWARF_ALT_FRAME_RETURN_COLUMN); + Builder.CreateStore(Size, Builder.CreateGEP(Addr, Idx, "tmp"), false); +#endif + + // TODO: the RS6000 target needs extra initialization [gcc changeset 122468]. + + return true; +} + +bool TreeToLLVM::EmitBuiltinUnwindInit(tree exp, Value *&Result) { + if (!validate_arglist(TREE_OPERAND(exp, 1), VOID_TYPE)) + return false; + + Result = Builder.CreateCall(Intrinsic::getDeclaration(TheModule, + Intrinsic::eh_unwind_init)); + + return true; +} + bool TreeToLLVM::EmitBuiltinStackRestore(tree exp) { tree arglist = TREE_OPERAND(exp, 1); if (!validate_arglist(arglist, POINTER_TYPE, VOID_TYPE)) Modified: apple-local/branches/llvm/gcc/llvm-internal.h =================================================================== --- apple-local/branches/llvm/gcc/llvm-internal.h 2007-07-14 07:20:19 UTC (rev 129554) +++ apple-local/branches/llvm/gcc/llvm-internal.h 2007-07-14 18:39:13 UTC (rev 129555) @@ -562,6 +562,12 @@ bool EmitBuiltinFrobReturnAddr(tree_node *exp, Value *&Result); bool EmitBuiltinStackSave(tree_node *exp, Value *&Result); bool EmitBuiltinStackRestore(tree_node *exp); + bool EmitBuiltinDwarfCFA(tree_node *exp, Value *&Result); + bool EmitBuiltinDwarfSPColumn(tree_node *exp, Value *&Result); + bool EmitBuiltinEHReturnDataRegno(tree_node *exp, Value *&Result); + bool EmitBuiltinEHReturn(tree_node *exp, Value *&Result); + bool EmitBuiltinInitDwarfRegSizes(tree_node *exp, Value *&Result); + bool EmitBuiltinUnwindInit(tree_node *exp, Value *&Result); // Complex Math Expressions. void EmitLoadFromComplex(Value *&Real, Value *&Imag, Value *SrcComplex, _______________________________________________ llvm-commits mailing list llvm-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits